From 85fb95cdffdd95f2f908ee71974cae06b1c866e1 Mon Sep 17 00:00:00 2001 From: Sam Zhou Date: Fri, 16 Aug 2024 12:53:52 -0400 Subject: [PATCH 001/426] [flow] Eliminate a few React.Element type that will be synced to react-native (#30719) ## Summary Flow will eventually remove the specific `React.Element` type. For most of the code, it can be replaced with `React.MixedElement` or `React.Node`. When specific react elements are required, it needs to be replaced with either `React$Element` which will trigger a `internal-type` lint error that can be disabled project-wide, or use `ExactReactElement_DEPRECATED`. Fortunately in this case, this one can be replaced with just `React.MixedElement`. ## How did you test this change? `flow` --- .../react-native-renderer/src/ReactNativeRenderer.js | 4 ++-- .../react-native-renderer/src/ReactNativeTypes.js | 11 ++++++++--- packages/react/index.js | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/react-native-renderer/src/ReactNativeRenderer.js b/packages/react-native-renderer/src/ReactNativeRenderer.js index 983079fd0eeb3..4ec5ab2c58529 100644 --- a/packages/react-native-renderer/src/ReactNativeRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeRenderer.js @@ -8,7 +8,7 @@ */ import type {ReactPortal, ReactNodeList} from 'shared/ReactTypes'; -import type {ElementRef, Element, ElementType} from 'react'; +import type {ElementRef, ElementType, MixedElement} from 'react'; import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes'; import type {RenderRootOptions} from './ReactNativeTypes'; @@ -117,7 +117,7 @@ function nativeOnCaughtError( } function render( - element: Element, + element: MixedElement, containerTag: number, callback: ?() => void, options: ?RenderRootOptions, diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 917e3988c7b38..210366842383e 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -9,7 +9,12 @@ * @flow strict */ -import type {ElementRef, ElementType, Element, AbstractComponent} from 'react'; +import type { + ElementRef, + ElementType, + MixedElement, + AbstractComponent, +} from 'react'; export type MeasureOnSuccessCallback = ( x: number, @@ -221,7 +226,7 @@ export type ReactNativeType = { eventType: string, ): void, render( - element: Element, + element: MixedElement, containerTag: number, callback: ?() => void, options: ?RenderRootOptions, @@ -256,7 +261,7 @@ export type ReactFabricType = { eventType: string, ): void, render( - element: Element, + element: MixedElement, containerTag: number, callback: ?() => void, concurrentRoot: ?boolean, diff --git a/packages/react/index.js b/packages/react/index.js index bad2c40e6c3dd..19f256fd73b5b 100644 --- a/packages/react/index.js +++ b/packages/react/index.js @@ -15,6 +15,7 @@ export type AbstractComponent< > = React$AbstractComponent; export type ElementType = React$ElementType; export type Element<+C> = React$Element; +export type MixedElement = React$Element; export type Key = React$Key; export type Ref = React$Ref; export type Node = React$Node; From 5030e08575c295ef352c5ae928e2366cc4765d32 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 16 Aug 2024 13:27:13 -0400 Subject: [PATCH 002/426] [compiler] Exclude refs and ref values from having mutable ranges Summary: Refs, as stable values that the rules of react around mutability do not apply to, currently are treated as having mutable ranges, and through aliasing, this can extend the mutable range for other values and disrupt good memoization for those values. This PR excludes refs and their .current values from having mutable ranges. Note that this is unsafe if ref access is allowed in render: if a mutable value is assigned to ref.current and then ref.current is mutated later, we won't realize that the original mutable value's range extends. ghstack-source-id: e8f36ac25e2c9aadb0bf13bd8142e4593ee9f984 Pull Request resolved: https://github.com/facebook/react/pull/30713 --- .../src/HIR/HIR.ts | 4 ++ .../src/Inference/AnalyseFunctions.ts | 5 +- .../src/Inference/InferMutableLifetimes.ts | 10 +++- .../Inference/InferMutableRangesForAlias.ts | 15 ++++-- .../src/Inference/InferReferenceEffects.ts | 13 ++--- .../Validation/ValidateNoRefAccesInRender.ts | 4 +- .../capture-ref-for-later-mutation.expect.md | 29 +++++----- ...ified-later-preserve-memoization.expect.md | 6 ++- ...ref-modified-later-preserve-memoization.js | 2 +- ...a-function-preserve-memoization.expect.md} | 8 ++- ...ater-via-function-preserve-memoization.js} | 2 +- .../capture-ref-for-later-mutation.expect.md | 42 +++++---------- ....maybe-mutable-ref-not-preserved.expect.md | 35 ------------ .../maybe-mutable-ref-not-preserved.expect.md | 53 +++++++++++++++++++ ....ts => maybe-mutable-ref-not-preserved.ts} | 0 .../repro-ref-mutable-range.expect.md | 34 +++++++----- ...operty-dont-preserve-memoization.expect.md | 27 ++++++---- 17 files changed, 159 insertions(+), 130 deletions(-) rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md => error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md} (68%) rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js => error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js} (88%) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/{error.maybe-mutable-ref-not-preserved.ts => maybe-mutable-ref-not-preserved.ts} (100%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index e61665ce4c6bb..0810130102b0e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -1591,6 +1591,10 @@ export function isUseStateType(id: Identifier): boolean { return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseState'; } +export function isRefOrRefValue(id: Identifier): boolean { + return isUseRefType(id) || isRefValueType(id); +} + export function isSetStateType(id: Identifier): boolean { return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetState'; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts index b18e19606ce0d..fbb24ea492c0f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts @@ -14,8 +14,7 @@ import { LoweredFunction, Place, ReactiveScopeDependency, - isRefValueType, - isUseRefType, + isRefOrRefValue, makeInstructionId, } from '../HIR'; import {deadCodeElimination} from '../Optimization'; @@ -139,7 +138,7 @@ function infer( name = dep.identifier.name; } - if (isUseRefType(dep.identifier) || isRefValueType(dep.identifier)) { + if (isRefOrRefValue(dep.identifier)) { /* * TODO: this is a hack to ensure we treat functions which reference refs * as having a capture and therefore being considered mutable. this ensures diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts index 2ce1aebbf8577..459baf4e287cc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts @@ -11,6 +11,7 @@ import { Identifier, InstructionId, InstructionKind, + isRefOrRefValue, makeInstructionId, Place, } from '../HIR/HIR'; @@ -66,7 +67,9 @@ import {assertExhaustive} from '../Utils/utils'; */ function infer(place: Place, instrId: InstructionId): void { - place.identifier.mutableRange.end = makeInstructionId(instrId + 1); + if (!isRefOrRefValue(place.identifier)) { + place.identifier.mutableRange.end = makeInstructionId(instrId + 1); + } } function inferPlace( @@ -171,7 +174,10 @@ export function inferMutableLifetimes( const declaration = contextVariableDeclarationInstructions.get( instr.value.lvalue.place.identifier, ); - if (declaration != null) { + if ( + declaration != null && + !isRefOrRefValue(instr.value.lvalue.place.identifier) + ) { const range = instr.value.lvalue.place.identifier.mutableRange; if (range.start === 0) { range.start = declaration; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableRangesForAlias.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableRangesForAlias.ts index 975acf6fbf55a..a7e8b5c1f7a80 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableRangesForAlias.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableRangesForAlias.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {HIRFunction, Identifier, InstructionId} from '../HIR/HIR'; +import { + HIRFunction, + Identifier, + InstructionId, + isRefOrRefValue, +} from '../HIR/HIR'; import DisjointSet from '../Utils/DisjointSet'; export function inferMutableRangesForAlias( @@ -19,7 +24,8 @@ export function inferMutableRangesForAlias( * mutated. */ const mutatingIdentifiers = [...aliasSet].filter( - id => id.mutableRange.end - id.mutableRange.start > 1, + id => + id.mutableRange.end - id.mutableRange.start > 1 && !isRefOrRefValue(id), ); if (mutatingIdentifiers.length > 0) { @@ -36,7 +42,10 @@ export function inferMutableRangesForAlias( * last mutation. */ for (const alias of aliasSet) { - if (alias.mutableRange.end < lastMutatingInstructionId) { + if ( + alias.mutableRange.end < lastMutatingInstructionId && + !isRefOrRefValue(alias) + ) { alias.mutableRange.end = lastMutatingInstructionId as InstructionId; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 356bc8af08bfd..4cce942c18154 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -30,8 +30,7 @@ import { isArrayType, isMutableEffect, isObjectType, - isRefValueType, - isUseRefType, + isRefOrRefValue, } from '../HIR/HIR'; import {FunctionSignature} from '../HIR/ObjectShape'; import { @@ -523,10 +522,7 @@ class InferenceState { break; } case Effect.Mutate: { - if ( - isRefValueType(place.identifier) || - isUseRefType(place.identifier) - ) { + if (isRefOrRefValue(place.identifier)) { // no-op: refs are validate via ValidateNoRefAccessInRender } else if (valueKind.kind === ValueKind.Context) { functionEffect = { @@ -567,10 +563,7 @@ class InferenceState { break; } case Effect.Store: { - if ( - isRefValueType(place.identifier) || - isUseRefType(place.identifier) - ) { + if (isRefOrRefValue(place.identifier)) { // no-op: refs are validate via ValidateNoRefAccessInRender } else if (valueKind.kind === ValueKind.Context) { functionEffect = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index b4fb2a618ada4..a93664f418f8e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -11,6 +11,7 @@ import { IdentifierId, Place, SourceLocation, + isRefOrRefValue, isRefValueType, isUseRefType, } from '../HIR'; @@ -231,8 +232,7 @@ function validateNoRefAccess( loc: SourceLocation, ): void { if ( - isRefValueType(operand.identifier) || - isUseRefType(operand.identifier) || + isRefOrRefValue(operand.identifier) || refAccessingFunctions.has(operand.identifier.id) ) { errors.push({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md index 41748867b35d5..b7371108d5867 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md @@ -36,27 +36,26 @@ import { useRef } from "react"; import { addOne } from "shared-runtime"; function useKeyCommand() { - const $ = _c(2); + const $ = _c(1); const currentPosition = useRef(0); - const handleKey = (direction) => () => { - const position = currentPosition.current; - const nextPosition = direction === "left" ? addOne(position) : position; - currentPosition.current = nextPosition; - }; + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + const handleKey = (direction) => () => { + const position = currentPosition.current; + const nextPosition = direction === "left" ? addOne(position) : position; + currentPosition.current = nextPosition; + }; - const moveLeft = { handler: handleKey("left") }; + const moveLeft = { handler: handleKey("left") }; - const t0 = handleKey("right"); - let t1; - if ($[0] !== t0) { - t1 = { handler: t0 }; + const moveRight = { handler: handleKey("right") }; + + t0 = [moveLeft, moveRight]; $[0] = t0; - $[1] = t1; } else { - t1 = $[1]; + t0 = $[0]; } - const moveRight = t1; - return [moveLeft, moveRight]; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md index 5eeb8c6b0ab89..c79ceca9efcee 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @enablePreserveExistingMemoizationGuarantees +// @enablePreserveExistingMemoizationGuarantees @validateRefAccessDuringRender import {useCallback, useRef} from 'react'; function Component(props) { @@ -42,7 +42,9 @@ export const FIXTURE_ENTRYPOINT = { > 10 | ref.current.inner = event.target.value; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > 11 | }); - | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (7:11) + | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $44:TObject (7:11) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) 12 | 13 | // The ref is modified later, extending its range and preventing memoization of onChange 14 | ref.current.inner = null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.js index b209be7586992..cb259b457e3e3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.js @@ -1,4 +1,4 @@ -// @enablePreserveExistingMemoizationGuarantees +// @enablePreserveExistingMemoizationGuarantees @validateRefAccessDuringRender import {useCallback, useRef} from 'react'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md similarity index 68% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md index ad21b4ba8c5e9..045ac8c3d61cb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @enablePreserveExistingMemoizationGuarantees +// @enablePreserveExistingMemoizationGuarantees @validateRefAccessDuringRender import {useCallback, useRef} from 'react'; function Component(props) { @@ -45,7 +45,11 @@ export const FIXTURE_ENTRYPOINT = { > 10 | ref.current.inner = event.target.value; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > 11 | }); - | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (7:11) + | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $53:TObject (7:11) + +InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef). Function mutate? $77[20:22]:TObject accesses a ref (17:17) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (17:17) 12 | 13 | // The ref is modified later, extending its range and preventing memoization of onChange 14 | const reset = () => { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js similarity index 88% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js index 8e71ed63269d8..dec828c2d0d19 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.js @@ -1,4 +1,4 @@ -// @enablePreserveExistingMemoizationGuarantees +// @enablePreserveExistingMemoizationGuarantees @validateRefAccessDuringRender import {useCallback, useRef} from 'react'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md index 52cea4b047c05..54184be0f3f38 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md @@ -37,42 +37,26 @@ import { useRef } from "react"; import { addOne } from "shared-runtime"; function useKeyCommand() { - const $ = _c(6); + const $ = _c(1); const currentPosition = useRef(0); - const handleKey = (direction) => () => { - const position = currentPosition.current; - const nextPosition = direction === "left" ? addOne(position) : position; - currentPosition.current = nextPosition; - }; let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = { handler: handleKey("left") }; + const handleKey = (direction) => () => { + const position = currentPosition.current; + const nextPosition = direction === "left" ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + + const moveLeft = { handler: handleKey("left") }; + + const moveRight = { handler: handleKey("right") }; + + t0 = [moveLeft, moveRight]; $[0] = t0; } else { t0 = $[0]; } - const moveLeft = t0; - - const t1 = handleKey("right"); - let t2; - if ($[1] !== t1) { - t2 = { handler: t1 }; - $[1] = t1; - $[2] = t2; - } else { - t2 = $[2]; - } - const moveRight = t2; - let t3; - if ($[3] !== moveLeft || $[4] !== moveRight) { - t3 = [moveLeft, moveRight]; - $[3] = moveLeft; - $[4] = moveRight; - $[5] = t3; - } else { - t3 = $[5]; - } - return t3; + return t0; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md deleted file mode 100644 index 61fe8b8deb7ee..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md +++ /dev/null @@ -1,35 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees:true - -import {useRef, useMemo} from 'react'; -import {makeArray} from 'shared-runtime'; - -function useFoo() { - const r = useRef(); - return useMemo(() => makeArray(r), []); -} - -export const FIXTURE_ENTRYPOINT = { - fn: useFoo, - params: [], -}; - -``` - - -## Error - -``` - 6 | function useFoo() { - 7 | const r = useRef(); -> 8 | return useMemo(() => makeArray(r), []); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (8:8) - 9 | } - 10 | - 11 | export const FIXTURE_ENTRYPOINT = { -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md new file mode 100644 index 0000000000000..61ab6bafaecd1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md @@ -0,0 +1,53 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees:true + +import {useRef, useMemo} from 'react'; +import {makeArray} from 'shared-runtime'; + +function useFoo() { + const r = useRef(); + return useMemo(() => makeArray(r), []); +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees:true + +import { useRef, useMemo } from "react"; +import { makeArray } from "shared-runtime"; + +function useFoo() { + const $ = _c(1); + const r = useRef(); + let t0; + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t1 = makeArray(r); + $[0] = t1; + } else { + t1 = $[0]; + } + t0 = t1; + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [], +}; + +``` + +### Eval output +(kind: ok) [{}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.ts similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.ts rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md index 96fd656ca3003..8b656b8e23b27 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md @@ -31,7 +31,7 @@ import { c as _c } from "react/compiler-runtime"; import { Stringify, identity, mutate, CONST_TRUE } from "shared-runtime"; function Foo(props, ref) { - const $ = _c(5); + const $ = _c(7); let value; let t0; if ($[0] !== ref) { @@ -45,19 +45,6 @@ function Foo(props, ref) { } mutate(value); - if (CONST_TRUE) { - const t1 = identity(ref); - let t2; - if ($[3] !== t1) { - t2 = ; - $[3] = t1; - $[4] = t2; - } else { - t2 = $[4]; - } - t0 = t2; - break bb0; - } } $[0] = ref; $[1] = value; @@ -69,6 +56,25 @@ function Foo(props, ref) { if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; } + if (CONST_TRUE) { + let t1; + if ($[3] !== ref) { + t1 = identity(ref); + $[3] = ref; + $[4] = t1; + } else { + t1 = $[4]; + } + let t2; + if ($[5] !== t1) { + t2 = ; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; + } return value; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md index e13d5a82c39b9..1efca9f0066be 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md @@ -42,21 +42,26 @@ function Component(props) { t0 = $[0]; } const ref = useRef(t0); - - const onChange = (event) => { - ref.current.inner = event.target.value; - }; + let t1; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t1 = (event) => { + ref.current.inner = event.target.value; + }; + $[1] = t1; + } else { + t1 = $[1]; + } + const onChange = t1; ref.current.inner = null; - let t1; - if ($[1] !== onChange) { - t1 = ; - $[1] = onChange; - $[2] = t1; + let t2; + if ($[2] === Symbol.for("react.memo_cache_sentinel")) { + t2 = ; + $[2] = t2; } else { - t1 = $[2]; + t2 = $[2]; } - return t1; + return t2; } export const FIXTURE_ENTRYPOINT = { From 7468ac530e73992f28169ac69e18395a75edfc47 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 16 Aug 2024 13:27:13 -0400 Subject: [PATCH 003/426] [compiler] Fixture to show ref-in-render enforcement issue with useCallback Test Plan: Documents that useCallback calls interfere with it being ok for refs to escape as part of functions into jsx ghstack-source-id: a5df427981ca32406fb2325e583b64bbe26b1cdd Pull Request resolved: https://github.com/facebook/react/pull/30714 --- .../error.return-ref-callback.expect.md | 37 +++++++++++++++++ .../compiler/error.return-ref-callback.js | 16 ++++++++ .../error.useCallback-ref-in-render.expect.md | 41 +++++++++++++++++++ .../error.useCallback-ref-in-render.js | 16 ++++++++ 4 files changed, 110 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md new file mode 100644 index 0000000000000..ae42ba1ee5422 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md @@ -0,0 +1,37 @@ + +## Input + +```javascript +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +component Foo() { + const ref = useRef(); + + const s = () => { + return ref.current; + }; + + return s; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + + +## Error + +``` + 8 | }; + 9 | +> 10 | return s; + | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $25:TObject (10:10) + 11 | } + 12 | + 13 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js new file mode 100644 index 0000000000000..3a650cdeed8e8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js @@ -0,0 +1,16 @@ +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +component Foo() { + const ref = useRef(); + + const s = () => { + return ref.current; + }; + + return s; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md new file mode 100644 index 0000000000000..ad1c0e7c3fe3a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md @@ -0,0 +1,41 @@ + +## Input + +```javascript +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +component Foo() { + const ref = useRef(); + + const s = useCallback(() => { + return ref.current; + }); + + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + + +## Error + +``` + 4 | const ref = useRef(); + 5 | +> 6 | const s = useCallback(() => { + | ^^^^^^^ +> 7 | return ref.current; + | ^^^^^^^^^^^^^^^^^^^^^^^ +> 8 | }); + | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $27:TObject (6:8) + 9 | + 10 | return ; + 11 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js new file mode 100644 index 0000000000000..3fc086164d607 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js @@ -0,0 +1,16 @@ +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +component Foo() { + const ref = useRef(); + + const s = useCallback(() => { + return ref.current; + }); + + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; From 8a531601115927400aa04d26a5f1800d159e1e7e Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 16 Aug 2024 13:27:13 -0400 Subject: [PATCH 004/426] [compiler] Don't error on ref-in-render on StartMemoize Test Plan: Fixes the previous issue: ref enforcement ignores memoization marker instructions ghstack-source-id: f35d6a611c5e740e9ea354ec80c3d7cdb3c0d658 Pull Request resolved: https://github.com/facebook/react/pull/30715 --- .../Validation/ValidateNoRefAccesInRender.ts | 3 + ...ified-later-preserve-memoization.expect.md | 20 ++--- ...ia-function-preserve-memoization.expect.md | 24 ++---- .../error.useCallback-ref-in-render.expect.md | 41 ---------- .../useCallback-ref-in-render.expect.md | 76 +++++++++++++++++++ ...render.js => useCallback-ref-in-render.js} | 7 +- 6 files changed, 97 insertions(+), 74 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.useCallback-ref-in-render.js => useCallback-ref-in-render.js} (70%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index a93664f418f8e..a855d9f8b414e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -185,6 +185,9 @@ function validateNoRefAccessInRenderImpl( } break; } + case 'StartMemoize': + case 'FinishMemoize': + break; default: { for (const operand of eachInstructionValueOperand(instr.value)) { validateNoRefValueAccess(errors, refAccessingFunctions, operand); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md index c79ceca9efcee..bff8f0e01f582 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md @@ -31,23 +31,13 @@ export const FIXTURE_ENTRYPOINT = { ## Error ``` - 5 | const ref = useRef({inner: null}); - 6 | -> 7 | const onChange = useCallback(event => { - | ^^^^^^^^^^ -> 8 | // The ref should still be mutable here even though function deps are frozen in - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 9 | // @enablePreserveExistingMemoizationGuarantees mode - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 10 | ref.current.inner = event.target.value; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 11 | }); - | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $44:TObject (7:11) - -InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) 12 | 13 | // The ref is modified later, extending its range and preventing memoization of onChange - 14 | ref.current.inner = null; +> 14 | ref.current.inner = null; + | ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) + 15 | + 16 | return ; + 17 | } ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md index 045ac8c3d61cb..9014de67d4478 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md @@ -34,25 +34,15 @@ export const FIXTURE_ENTRYPOINT = { ## Error ``` - 5 | const ref = useRef({inner: null}); - 6 | -> 7 | const onChange = useCallback(event => { - | ^^^^^^^^^^ -> 8 | // The ref should still be mutable here even though function deps are frozen in - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 9 | // @enablePreserveExistingMemoizationGuarantees mode - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 10 | ref.current.inner = event.target.value; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 11 | }); - | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $53:TObject (7:11) - -InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef). Function mutate? $77[20:22]:TObject accesses a ref (17:17) + 15 | ref.current.inner = null; + 16 | }; +> 17 | reset(); + | ^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef). Function mutate? $77[20:22]:TObject accesses a ref (17:17) InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (17:17) - 12 | - 13 | // The ref is modified later, extending its range and preventing memoization of onChange - 14 | const reset = () => { + 18 | + 19 | return ; + 20 | } ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md deleted file mode 100644 index ad1c0e7c3fe3a..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.expect.md +++ /dev/null @@ -1,41 +0,0 @@ - -## Input - -```javascript -// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees - -component Foo() { - const ref = useRef(); - - const s = useCallback(() => { - return ref.current; - }); - - return ; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [], -}; - -``` - - -## Error - -``` - 4 | const ref = useRef(); - 5 | -> 6 | const s = useCallback(() => { - | ^^^^^^^ -> 7 | return ref.current; - | ^^^^^^^^^^^^^^^^^^^^^^^ -> 8 | }); - | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $27:TObject (6:8) - 9 | - 10 | return ; - 11 | } -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.expect.md new file mode 100644 index 0000000000000..e1427437ce86d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.expect.md @@ -0,0 +1,76 @@ + +## Input + +```javascript +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees +import {useCallback, useRef} from 'react'; + +component Foo() { + const ref = useRef(); + + const s = useCallback(() => { + return ref.current; + }); + + return ; +} + +component A(r: mixed) { + return
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useCallback, useRef } from "react"; + +function Foo() { + const $ = _c(2); + const ref = useRef(); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = () => ref.current; + $[0] = t0; + } else { + t0 = $[0]; + } + const s = t0; + let t1; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t1 = ; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +function A(t0) { + const $ = _c(1); + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t1 =
; + $[0] = t1; + } else { + t1 = $[0]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + +### Eval output +(kind: ok)
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.js similarity index 70% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.js index 3fc086164d607..9fefa503203e2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-ref-in-render.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-ref-in-render.js @@ -1,4 +1,5 @@ // @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees +import {useCallback, useRef} from 'react'; component Foo() { const ref = useRef(); @@ -7,7 +8,11 @@ component Foo() { return ref.current; }); - return
; + return ; +} + +component A(r: mixed) { + return
; } export const FIXTURE_ENTRYPOINT = { From 1016174af520fc89bafab7189405fce8ff3a9bb5 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 16 Aug 2024 13:27:13 -0400 Subject: [PATCH 005/426] [compiler] Reposition ref-in-render errors to the read location of .current Summary: Since we want to make ref-in-render errors enabled by default, we should position those errors at the location of the read. Not only will this be a better experience, but it also aligns the behavior of Forget and Flow. This PR also cleans up the resulting error messages to not emit implementation details about place values. ghstack-source-id: 1d1131706867a6fc88efddd631c4d16d2181e592 Pull Request resolved: https://github.com/facebook/react/pull/30723 --- .../Validation/ValidateNoRefAccesInRender.ts | 73 +++++++++++++++---- ...invalid-access-ref-during-render.expect.md | 7 +- ...tating-refs-in-render-transitive.expect.md | 2 +- ...d-ref-prop-in-render-destructure.expect.md | 7 +- ...ref-prop-in-render-property-load.expect.md | 7 +- ...error.invalid-ref-value-as-props.expect.md | 2 +- ...d-set-and-read-ref-during-render.expect.md | 2 +- ...ef-nested-property-during-render.expect.md | 4 +- .../error.return-ref-callback.expect.md | 2 +- ...ified-later-preserve-memoization.expect.md | 2 +- ...ia-function-preserve-memoization.expect.md | 2 +- 11 files changed, 79 insertions(+), 31 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index a855d9f8b414e..4da6b23a1a9ed 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -15,7 +15,6 @@ import { isRefValueType, isUseRefType, } from '../HIR'; -import {printPlace} from '../HIR/PrintHIR'; import { eachInstructionValueOperand, eachTerminalOperand, @@ -53,6 +52,7 @@ function validateNoRefAccessInRenderImpl( refAccessingFunctions: Set, ): Result { const errors = new CompilerError(); + const lookupLocations: Map = new Map(); for (const [, block] of fn.body.blocks) { for (const instr of block.instructions) { switch (instr.value.kind) { @@ -64,10 +64,12 @@ function validateNoRefAccessInRenderImpl( severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: operand.loc, - description: `Cannot access ref value at ${printPlace( - operand, - )}`, + loc: lookupLocations.get(operand.identifier.id) ?? operand.loc, + description: + operand.identifier.name !== null && + operand.identifier.name.kind === 'named' + ? `Cannot access ref value \`${operand.identifier.name.value}\`` + : null, suggestions: null, }); } @@ -75,12 +77,24 @@ function validateNoRefAccessInRenderImpl( break; } case 'PropertyLoad': { + if ( + isRefValueType(instr.lvalue.identifier) && + instr.value.property === 'current' + ) { + lookupLocations.set(instr.lvalue.identifier.id, instr.loc); + } break; } case 'LoadLocal': { if (refAccessingFunctions.has(instr.value.place.identifier.id)) { refAccessingFunctions.add(instr.lvalue.identifier.id); } + if (isRefValueType(instr.lvalue.identifier)) { + const loc = lookupLocations.get(instr.value.place.identifier.id); + if (loc !== undefined) { + lookupLocations.set(instr.lvalue.identifier.id, loc); + } + } break; } case 'StoreLocal': { @@ -88,6 +102,13 @@ function validateNoRefAccessInRenderImpl( refAccessingFunctions.add(instr.value.lvalue.place.identifier.id); refAccessingFunctions.add(instr.lvalue.identifier.id); } + if (isRefValueType(instr.value.lvalue.place.identifier)) { + const loc = lookupLocations.get(instr.value.value.identifier.id); + if (loc !== undefined) { + lookupLocations.set(instr.value.lvalue.place.identifier.id, loc); + lookupLocations.set(instr.lvalue.identifier.id, loc); + } + } break; } case 'ObjectMethod': @@ -140,7 +161,11 @@ function validateNoRefAccessInRenderImpl( reason: 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)', loc: callee.loc, - description: `Function ${printPlace(callee)} accesses a ref`, + description: + callee.identifier.name !== null && + callee.identifier.name.kind === 'named' + ? `Function \`${callee.identifier.name.value}\` accesses a ref` + : null, suggestions: null, }); } @@ -149,7 +174,7 @@ function validateNoRefAccessInRenderImpl( errors, refAccessingFunctions, operand, - operand.loc, + lookupLocations.get(operand.identifier.id) ?? operand.loc, ); } } @@ -162,7 +187,7 @@ function validateNoRefAccessInRenderImpl( errors, refAccessingFunctions, operand, - operand.loc, + lookupLocations.get(operand.identifier.id) ?? operand.loc, ); } break; @@ -175,13 +200,18 @@ function validateNoRefAccessInRenderImpl( errors, refAccessingFunctions, instr.value.object, - instr.loc, + lookupLocations.get(instr.value.object.identifier.id) ?? instr.loc, ); for (const operand of eachInstructionValueOperand(instr.value)) { if (operand === instr.value.object) { continue; } - validateNoRefValueAccess(errors, refAccessingFunctions, operand); + validateNoRefValueAccess( + errors, + refAccessingFunctions, + lookupLocations, + operand, + ); } break; } @@ -190,14 +220,24 @@ function validateNoRefAccessInRenderImpl( break; default: { for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefValueAccess(errors, refAccessingFunctions, operand); + validateNoRefValueAccess( + errors, + refAccessingFunctions, + lookupLocations, + operand, + ); } break; } } } for (const operand of eachTerminalOperand(block.terminal)) { - validateNoRefValueAccess(errors, refAccessingFunctions, operand); + validateNoRefValueAccess( + errors, + refAccessingFunctions, + lookupLocations, + operand, + ); } } @@ -211,6 +251,7 @@ function validateNoRefAccessInRenderImpl( function validateNoRefValueAccess( errors: CompilerError, refAccessingFunctions: Set, + lookupLocations: Map, operand: Place, ): void { if ( @@ -221,8 +262,12 @@ function validateNoRefValueAccess( severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: operand.loc, - description: `Cannot access ref value at ${printPlace(operand)}`, + loc: lookupLocations.get(operand.identifier.id) ?? operand.loc, + description: + operand.identifier.name !== null && + operand.identifier.name.kind === 'named' + ? `Cannot access ref value \`${operand.identifier.name.value}\`` + : null, suggestions: null, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md index c5e8b68c04002..02748366456fb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-access-ref-during-render.expect.md @@ -15,10 +15,11 @@ function Component(props) { ## Error ``` + 2 | function Component(props) { 3 | const ref = useRef(null); - 4 | const value = ref.current; -> 5 | return value; - | ^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $22:TObject (5:5) +> 4 | const value = ref.current; + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4) + 5 | return value; 6 | } 7 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md index 0d4cb1318911b..f23ff6f3c8c57 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-disallow-mutating-refs-in-render-transitive.expect.md @@ -24,7 +24,7 @@ function Component() { 7 | }; 8 | const changeRef = setRef; > 9 | changeRef(); - | ^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef). Function mutate? $39[11:13]:TObject accesses a ref (9:9) + | ^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9) InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9) 10 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md index d8e8174d2cc62..100dafaf38a88 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-destructure.expect.md @@ -14,10 +14,11 @@ function Component({ref}) { ## Error ``` + 1 | // @validateRefAccessDuringRender @compilationMode(infer) 2 | function Component({ref}) { - 3 | const value = ref.current; -> 4 | return
{value}
; - | ^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $17:TObject (4:4) +> 3 | const value = ref.current; + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (3:3) + 4 | return
{value}
; 5 | } 6 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md index e374900a95ad4..4d8c4c735c70e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-read-ref-prop-in-render-property-load.expect.md @@ -14,10 +14,11 @@ function Component(props) { ## Error ``` + 1 | // @validateRefAccessDuringRender @compilationMode(infer) 2 | function Component(props) { - 3 | const value = props.ref.current; -> 4 | return
{value}
; - | ^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at read $15:TObject (4:4) +> 3 | const value = props.ref.current; + | ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (3:3) + 4 | return
{value}
; 5 | } 6 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md index 96e2ca9a1ef28..f86f6b7a39145 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-ref-value-as-props.expect.md @@ -17,7 +17,7 @@ function Component(props) { 2 | function Component(props) { 3 | const ref = useRef(null); > 4 | return ; - | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $19:TObject (4:4) + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4) 5 | } 6 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md index 5db1568427835..d38adb5589db3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-during-render.expect.md @@ -20,7 +20,7 @@ function Component(props) { > 4 | ref.current = props.value; | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4) -InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $24:TObject (5:5) +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5) 5 | return ref.current; 6 | } 7 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md index 290b8539e7b14..527adfc6e9fc5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-set-and-read-ref-nested-property-during-render.expect.md @@ -18,9 +18,9 @@ function Component(props) { 2 | function Component(props) { 3 | const ref = useRef({inner: null}); > 4 | ref.current.inner = props.value; - | ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4) + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (4:4) -InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $30:TObject (5:5) +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5) 5 | return ref.current.inner; 6 | } 7 | diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md index ae42ba1ee5422..98f2a86714034 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md @@ -28,7 +28,7 @@ export const FIXTURE_ENTRYPOINT = { 8 | }; 9 | > 10 | return s; - | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value at freeze $25:TObject (10:10) + | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (10:10) 11 | } 12 | 13 | export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md index bff8f0e01f582..7a8f271bd2879 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-useCallback-set-ref-nested-property-ref-modified-later-preserve-memoization.expect.md @@ -34,7 +34,7 @@ export const FIXTURE_ENTRYPOINT = { 12 | 13 | // The ref is modified later, extending its range and preventing memoization of onChange > 14 | ref.current.inner = null; - | ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) 15 | 16 | return ; 17 | } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md index 9014de67d4478..f3ab9816218f9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-accesses-ref-mutated-later-via-function-preserve-memoization.expect.md @@ -37,7 +37,7 @@ export const FIXTURE_ENTRYPOINT = { 15 | ref.current.inner = null; 16 | }; > 17 | reset(); - | ^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef). Function mutate? $77[20:22]:TObject accesses a ref (17:17) + | ^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (17:17) InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (17:17) 18 | From 21a95239e15cf62e4bf3922af998383b844df2e3 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 16 Aug 2024 13:27:13 -0400 Subject: [PATCH 006/426] [compiler] Allow functions containing refs to be returned Summary: We previously were excessively strict about preventing functions that access refs from being returned--doing so is potentially valid for hooks, because the return value may only be used in an event or effect. ghstack-source-id: cfa8bb1b54e8eb365f2de50d051bd09e09162d7b Pull Request resolved: https://github.com/facebook/react/pull/30724 --- .../Validation/ValidateNoRefAccesInRender.ts | 53 +++++++++++------- .../error.return-ref-callback.expect.md | 37 ------------- .../compiler/return-ref-callback.expect.md | 55 +++++++++++++++++++ ...ref-callback.js => return-ref-callback.js} | 2 + 4 files changed, 90 insertions(+), 57 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.return-ref-callback.js => return-ref-callback.js} (89%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index 4da6b23a1a9ed..df6241a73f448 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -59,20 +59,7 @@ function validateNoRefAccessInRenderImpl( case 'JsxExpression': case 'JsxFragment': { for (const operand of eachInstructionValueOperand(instr.value)) { - if (isRefValueType(operand.identifier)) { - errors.push({ - severity: ErrorSeverity.InvalidReact, - reason: - 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: lookupLocations.get(operand.identifier.id) ?? operand.loc, - description: - operand.identifier.name !== null && - operand.identifier.name.kind === 'named' - ? `Cannot access ref value \`${operand.identifier.name.value}\`` - : null, - suggestions: null, - }); - } + validateNoDirectRefValueAccess(errors, operand, lookupLocations); } break; } @@ -232,12 +219,17 @@ function validateNoRefAccessInRenderImpl( } } for (const operand of eachTerminalOperand(block.terminal)) { - validateNoRefValueAccess( - errors, - refAccessingFunctions, - lookupLocations, - operand, - ); + if (block.terminal.kind !== 'return') { + validateNoRefValueAccess( + errors, + refAccessingFunctions, + lookupLocations, + operand, + ); + } else { + // Allow functions containing refs to be returned, but not direct ref values + validateNoDirectRefValueAccess(errors, operand, lookupLocations); + } } } @@ -297,3 +289,24 @@ function validateNoRefAccess( }); } } + +function validateNoDirectRefValueAccess( + errors: CompilerError, + operand: Place, + lookupLocations: Map, +): void { + if (isRefValueType(operand.identifier)) { + errors.push({ + severity: ErrorSeverity.InvalidReact, + reason: + 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', + loc: lookupLocations.get(operand.identifier.id) ?? operand.loc, + description: + operand.identifier.name !== null && + operand.identifier.name.kind === 'named' + ? `Cannot access ref value \`${operand.identifier.name.value}\`` + : null, + suggestions: null, + }); + } +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md deleted file mode 100644 index 98f2a86714034..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.expect.md +++ /dev/null @@ -1,37 +0,0 @@ - -## Input - -```javascript -// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees - -component Foo() { - const ref = useRef(); - - const s = () => { - return ref.current; - }; - - return s; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [], -}; - -``` - - -## Error - -``` - 8 | }; - 9 | -> 10 | return s; - | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (10:10) - 11 | } - 12 | - 13 | export const FIXTURE_ENTRYPOINT = { -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.expect.md new file mode 100644 index 0000000000000..ed1dfa39ea55c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.expect.md @@ -0,0 +1,55 @@ + +## Input + +```javascript +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +import {useRef} from 'react'; + +component Foo() { + const ref = useRef(); + + const s = () => { + return ref.current; + }; + + return s; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; + +import { useRef } from "react"; + +function Foo() { + const $ = _c(1); + const ref = useRef(); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = () => ref.current; + $[0] = t0; + } else { + t0 = $[0]; + } + const s = t0; + return s; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [], +}; + +``` + +### Eval output +(kind: ok) "[[ function params=0 ]]" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.js similarity index 89% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.js index 3a650cdeed8e8..f1a45ebc4ff3e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback.js @@ -1,5 +1,7 @@ // @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees +import {useRef} from 'react'; + component Foo() { const ref = useRef(); From 5edbe29dbe945d821021a1152b267f5a86efc55b Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 16 Aug 2024 13:27:13 -0400 Subject: [PATCH 007/426] [compiler] Make ref enforcement on by default Summary: The change earlier in this stack makes it less safe to have ref enforcement disabled. This diff enables it by default. ghstack-source-id: d3ab5f1b28b7aed0f0d6d69547bb638a1e326b66 Pull Request resolved: https://github.com/facebook/react/pull/30716 --- .../src/HIR/Environment.ts | 2 +- .../capture-ref-for-later-mutation.expect.md | 69 -------------- ...r.capture-ref-for-later-mutation.expect.md | 50 +++++++++++ ... error.capture-ref-for-later-mutation.tsx} | 0 .../error.repro-ref-mutable-range.expect.md | 40 +++++++++ ....tsx => error.repro-ref-mutable-range.tsx} | 0 ...operty-dont-preserve-memoization.expect.md | 42 +++++++++ ...ted-property-dont-preserve-memoization.js} | 0 .../capture-ref-for-later-mutation.expect.md | 70 --------------- ...r.capture-ref-for-later-mutation.expect.md | 51 +++++++++++ ... error.capture-ref-for-later-mutation.tsx} | 0 ....maybe-mutable-ref-not-preserved.expect.md | 35 ++++++++ ... error.maybe-mutable-ref-not-preserved.ts} | 0 .../error.useMemo-with-refs.flow.expect.md | 31 +++++++ ...low.js => error.useMemo-with-refs.flow.js} | 0 .../maybe-mutable-ref-not-preserved.expect.md | 53 ----------- .../useMemo-with-refs.flow.expect.md | 54 ----------- .../repro-ref-mutable-range.expect.md | 89 ------------------- ...operty-dont-preserve-memoization.expect.md | 75 ---------------- .../src/__tests__/parseConfigPragma-test.ts | 6 +- .../__tests__/ReactCompilerRule-test.ts | 20 ++++- .../src/rules/ReactCompilerRule.ts | 5 +- 22 files changed, 275 insertions(+), 417 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{capture-ref-for-later-mutation.tsx => error.capture-ref-for-later-mutation.tsx} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-ref-mutable-range.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{repro-ref-mutable-range.tsx => error.repro-ref-mutable-range.tsx} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{useCallback-set-ref-nested-property-dont-preserve-memoization.js => error.useCallback-set-ref-nested-property-dont-preserve-memoization.js} (100%) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/error.capture-ref-for-later-mutation.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/{capture-ref-for-later-mutation.tsx => error.capture-ref-for-later-mutation.tsx} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/{maybe-mutable-ref-not-preserved.ts => error.maybe-mutable-ref-not-preserved.ts} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/{useMemo-with-refs.flow.js => error.useMemo-with-refs.flow.js} (100%) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-with-refs.flow.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 7eef0a7cc24b9..ca03b8a7b1e39 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -223,7 +223,7 @@ const EnvironmentConfigSchema = z.object({ validateHooksUsage: z.boolean().default(true), // Validate that ref values (`ref.current`) are not accessed during render. - validateRefAccessDuringRender: z.boolean().default(false), + validateRefAccessDuringRender: z.boolean().default(true), /* * Validates that setState is not unconditionally called during render, as it can lead to diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md deleted file mode 100644 index b7371108d5867..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md +++ /dev/null @@ -1,69 +0,0 @@ - -## Input - -```javascript -import {useRef} from 'react'; -import {addOne} from 'shared-runtime'; - -function useKeyCommand() { - const currentPosition = useRef(0); - const handleKey = direction => () => { - const position = currentPosition.current; - const nextPosition = direction === 'left' ? addOne(position) : position; - currentPosition.current = nextPosition; - }; - const moveLeft = { - handler: handleKey('left'), - }; - const moveRight = { - handler: handleKey('right'), - }; - return [moveLeft, moveRight]; -} - -export const FIXTURE_ENTRYPOINT = { - fn: useKeyCommand, - params: [], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; -import { useRef } from "react"; -import { addOne } from "shared-runtime"; - -function useKeyCommand() { - const $ = _c(1); - const currentPosition = useRef(0); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const handleKey = (direction) => () => { - const position = currentPosition.current; - const nextPosition = direction === "left" ? addOne(position) : position; - currentPosition.current = nextPosition; - }; - - const moveLeft = { handler: handleKey("left") }; - - const moveRight = { handler: handleKey("right") }; - - t0 = [moveLeft, moveRight]; - $[0] = t0; - } else { - t0 = $[0]; - } - return t0; -} - -export const FIXTURE_ENTRYPOINT = { - fn: useKeyCommand, - params: [], -}; - -``` - -### Eval output -(kind: ok) [{"handler":"[[ function params=0 ]]"},{"handler":"[[ function params=0 ]]"}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md new file mode 100644 index 0000000000000..52350036257d0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +import {useRef} from 'react'; +import {addOne} from 'shared-runtime'; + +function useKeyCommand() { + const currentPosition = useRef(0); + const handleKey = direction => () => { + const position = currentPosition.current; + const nextPosition = direction === 'left' ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + const moveLeft = { + handler: handleKey('left'), + }; + const moveRight = { + handler: handleKey('right'), + }; + return [moveLeft, moveRight]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; + +``` + + +## Error + +``` + 10 | }; + 11 | const moveLeft = { +> 12 | handler: handleKey('left'), + | ^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) + +InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (15:15) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (15:15) + 13 | }; + 14 | const moveRight = { + 15 | handler: handleKey('right'), +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.tsx similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.tsx rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-ref-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-ref-mutable-range.expect.md new file mode 100644 index 0000000000000..1e5fda2a35fb0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-ref-mutable-range.expect.md @@ -0,0 +1,40 @@ + +## Input + +```javascript +import {Stringify, identity, mutate, CONST_TRUE} from 'shared-runtime'; + +function Foo(props, ref) { + const value = {}; + if (CONST_TRUE) { + mutate(value); + return ; + } + mutate(value); + if (CONST_TRUE) { + return ; + } + return value; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{}, {current: 'fake-ref-object'}], +}; + +``` + + +## Error + +``` + 9 | mutate(value); + 10 | if (CONST_TRUE) { +> 11 | return ; + | ^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (11:11) + 12 | } + 13 | return value; + 14 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-ref-mutable-range.tsx similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.tsx rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.repro-ref-mutable-range.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md new file mode 100644 index 0000000000000..dbc3060a26f43 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md @@ -0,0 +1,42 @@ + +## Input + +```javascript +// @enablePreserveExistingMemoizationGuarantees:false +import {useCallback, useRef} from 'react'; + +function Component(props) { + const ref = useRef({inner: null}); + + const onChange = useCallback(event => { + // The ref should still be mutable here even though function deps are frozen in + // @enablePreserveExistingMemoizationGuarantees mode + ref.current.inner = event.target.value; + }); + + ref.current.inner = null; + + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{}], +}; + +``` + + +## Error + +``` + 11 | }); + 12 | +> 13 | ref.current.inner = null; + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (13:13) + 14 | + 15 | return ; + 16 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.useCallback-set-ref-nested-property-dont-preserve-memoization.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md deleted file mode 100644 index 54184be0f3f38..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md +++ /dev/null @@ -1,70 +0,0 @@ - -## Input - -```javascript -// @enableReactiveScopesInHIR:false -import {useRef} from 'react'; -import {addOne} from 'shared-runtime'; - -function useKeyCommand() { - const currentPosition = useRef(0); - const handleKey = direction => () => { - const position = currentPosition.current; - const nextPosition = direction === 'left' ? addOne(position) : position; - currentPosition.current = nextPosition; - }; - const moveLeft = { - handler: handleKey('left'), - }; - const moveRight = { - handler: handleKey('right'), - }; - return [moveLeft, moveRight]; -} - -export const FIXTURE_ENTRYPOINT = { - fn: useKeyCommand, - params: [], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @enableReactiveScopesInHIR:false -import { useRef } from "react"; -import { addOne } from "shared-runtime"; - -function useKeyCommand() { - const $ = _c(1); - const currentPosition = useRef(0); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const handleKey = (direction) => () => { - const position = currentPosition.current; - const nextPosition = direction === "left" ? addOne(position) : position; - currentPosition.current = nextPosition; - }; - - const moveLeft = { handler: handleKey("left") }; - - const moveRight = { handler: handleKey("right") }; - - t0 = [moveLeft, moveRight]; - $[0] = t0; - } else { - t0 = $[0]; - } - return t0; -} - -export const FIXTURE_ENTRYPOINT = { - fn: useKeyCommand, - params: [], -}; - -``` - -### Eval output -(kind: ok) [{"handler":"[[ function params=0 ]]"},{"handler":"[[ function params=0 ]]"}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/error.capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/error.capture-ref-for-later-mutation.expect.md new file mode 100644 index 0000000000000..f0b0e6f3a8679 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/error.capture-ref-for-later-mutation.expect.md @@ -0,0 +1,51 @@ + +## Input + +```javascript +// @enableReactiveScopesInHIR:false +import {useRef} from 'react'; +import {addOne} from 'shared-runtime'; + +function useKeyCommand() { + const currentPosition = useRef(0); + const handleKey = direction => () => { + const position = currentPosition.current; + const nextPosition = direction === 'left' ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + const moveLeft = { + handler: handleKey('left'), + }; + const moveRight = { + handler: handleKey('right'), + }; + return [moveLeft, moveRight]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; + +``` + + +## Error + +``` + 11 | }; + 12 | const moveLeft = { +> 13 | handler: handleKey('left'), + | ^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (13:13) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (13:13) + +InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (16:16) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (16:16) + 14 | }; + 15 | const moveRight = { + 16 | handler: handleKey('right'), +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/error.capture-ref-for-later-mutation.tsx similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.tsx rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/error.capture-ref-for-later-mutation.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md new file mode 100644 index 0000000000000..1ac3884f92f25 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees:true + +import {useRef, useMemo} from 'react'; +import {makeArray} from 'shared-runtime'; + +function useFoo() { + const r = useRef(); + return useMemo(() => makeArray(r), []); +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [], +}; + +``` + + +## Error + +``` + 6 | function useFoo() { + 7 | const r = useRef(); +> 8 | return useMemo(() => makeArray(r), []); + | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (8:8) + 9 | } + 10 | + 11 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.ts similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.ts rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.maybe-mutable-ref-not-preserved.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md new file mode 100644 index 0000000000000..de37e0d3d4391 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.expect.md @@ -0,0 +1,31 @@ + +## Input + +```javascript +// @flow @validatePreserveExistingMemoizationGuarantees +import {identity} from 'shared-runtime'; + +component Component(disableLocalRef, ref) { + const localRef = useFooRef(); + const mergedRef = useMemo(() => { + return disableLocalRef ? ref : identity(ref, localRef); + }, [disableLocalRef, ref, localRef]); + return
; +} + +``` + + +## Error + +``` + 5 | const localRef = useFooRef(); + 6 | const mergedRef = useMemo(() => { +> 7 | return disableLocalRef ? ref : identity(ref, localRef); + | ^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (7:7) + 8 | }, [disableLocalRef, ref, localRef]); + 9 | return
; + 10 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-with-refs.flow.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-with-refs.flow.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-with-refs.flow.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md deleted file mode 100644 index 61ab6bafaecd1..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/maybe-mutable-ref-not-preserved.expect.md +++ /dev/null @@ -1,53 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees:true - -import {useRef, useMemo} from 'react'; -import {makeArray} from 'shared-runtime'; - -function useFoo() { - const r = useRef(); - return useMemo(() => makeArray(r), []); -} - -export const FIXTURE_ENTRYPOINT = { - fn: useFoo, - params: [], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees:true - -import { useRef, useMemo } from "react"; -import { makeArray } from "shared-runtime"; - -function useFoo() { - const $ = _c(1); - const r = useRef(); - let t0; - let t1; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t1 = makeArray(r); - $[0] = t1; - } else { - t1 = $[0]; - } - t0 = t1; - return t0; -} - -export const FIXTURE_ENTRYPOINT = { - fn: useFoo, - params: [], -}; - -``` - -### Eval output -(kind: ok) [{}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-with-refs.flow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-with-refs.flow.expect.md deleted file mode 100644 index 1fc118ac59ba4..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-with-refs.flow.expect.md +++ /dev/null @@ -1,54 +0,0 @@ - -## Input - -```javascript -// @flow @validatePreserveExistingMemoizationGuarantees -import {identity} from 'shared-runtime'; - -component Component(disableLocalRef, ref) { - const localRef = useFooRef(); - const mergedRef = useMemo(() => { - return disableLocalRef ? ref : identity(ref, localRef); - }, [disableLocalRef, ref, localRef]); - return
; -} - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; -import { identity } from "shared-runtime"; - -const Component = React.forwardRef(Component_withRef); -function Component_withRef(t0, ref) { - const $ = _c(6); - const { disableLocalRef } = t0; - const localRef = useFooRef(); - let t1; - let t2; - if ($[0] !== disableLocalRef || $[1] !== ref || $[2] !== localRef) { - t2 = disableLocalRef ? ref : identity(ref, localRef); - $[0] = disableLocalRef; - $[1] = ref; - $[2] = localRef; - $[3] = t2; - } else { - t2 = $[3]; - } - t1 = t2; - const mergedRef = t1; - let t3; - if ($[4] !== mergedRef) { - t3 =
; - $[4] = mergedRef; - $[5] = t3; - } else { - t3 = $[5]; - } - return t3; -} - -``` - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md deleted file mode 100644 index 8b656b8e23b27..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-ref-mutable-range.expect.md +++ /dev/null @@ -1,89 +0,0 @@ - -## Input - -```javascript -import {Stringify, identity, mutate, CONST_TRUE} from 'shared-runtime'; - -function Foo(props, ref) { - const value = {}; - if (CONST_TRUE) { - mutate(value); - return ; - } - mutate(value); - if (CONST_TRUE) { - return ; - } - return value; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [{}, {current: 'fake-ref-object'}], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; -import { Stringify, identity, mutate, CONST_TRUE } from "shared-runtime"; - -function Foo(props, ref) { - const $ = _c(7); - let value; - let t0; - if ($[0] !== ref) { - t0 = Symbol.for("react.early_return_sentinel"); - bb0: { - value = {}; - if (CONST_TRUE) { - mutate(value); - t0 = ; - break bb0; - } - - mutate(value); - } - $[0] = ref; - $[1] = value; - $[2] = t0; - } else { - value = $[1]; - t0 = $[2]; - } - if (t0 !== Symbol.for("react.early_return_sentinel")) { - return t0; - } - if (CONST_TRUE) { - let t1; - if ($[3] !== ref) { - t1 = identity(ref); - $[3] = ref; - $[4] = t1; - } else { - t1 = $[4]; - } - let t2; - if ($[5] !== t1) { - t2 = ; - $[5] = t1; - $[6] = t2; - } else { - t2 = $[6]; - } - return t2; - } - return value; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [{}, { current: "fake-ref-object" }], -}; - -``` - -### Eval output -(kind: ok)
{"ref":{"current":"fake-ref-object"}}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md deleted file mode 100644 index 1efca9f0066be..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useCallback-set-ref-nested-property-dont-preserve-memoization.expect.md +++ /dev/null @@ -1,75 +0,0 @@ - -## Input - -```javascript -// @enablePreserveExistingMemoizationGuarantees:false -import {useCallback, useRef} from 'react'; - -function Component(props) { - const ref = useRef({inner: null}); - - const onChange = useCallback(event => { - // The ref should still be mutable here even though function deps are frozen in - // @enablePreserveExistingMemoizationGuarantees mode - ref.current.inner = event.target.value; - }); - - ref.current.inner = null; - - return ; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @enablePreserveExistingMemoizationGuarantees:false -import { useCallback, useRef } from "react"; - -function Component(props) { - const $ = _c(3); - let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = { inner: null }; - $[0] = t0; - } else { - t0 = $[0]; - } - const ref = useRef(t0); - let t1; - if ($[1] === Symbol.for("react.memo_cache_sentinel")) { - t1 = (event) => { - ref.current.inner = event.target.value; - }; - $[1] = t1; - } else { - t1 = $[1]; - } - const onChange = t1; - - ref.current.inner = null; - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = ; - $[2] = t2; - } else { - t2 = $[2]; - } - return t2; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{}], -}; - -``` - -### Eval output -(kind: ok) \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts index 8150a523263c7..706563b33b457 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts @@ -14,16 +14,16 @@ describe('parseConfigPragma()', () => { // Validate defaults first to make sure that the parser is getting the value from the pragma, // and not just missing it and getting the default value expect(defaultConfig.enableUseTypeAnnotations).toBe(false); - expect(defaultConfig.validateRefAccessDuringRender).toBe(false); + expect(defaultConfig.validateNoSetStateInPassiveEffects).toBe(false); expect(defaultConfig.validateNoSetStateInRender).toBe(true); const config = parseConfigPragma( - '@enableUseTypeAnnotations @validateRefAccessDuringRender:true @validateNoSetStateInRender:false', + '@enableUseTypeAnnotations @validateNoSetStateInPassiveEffects:true @validateNoSetStateInRender:false', ); expect(config).toEqual({ ...defaultConfig, enableUseTypeAnnotations: true, - validateRefAccessDuringRender: true, + validateNoSetStateInPassiveEffects: true, validateNoSetStateInRender: false, }); }); diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts index c87bcadbe98bc..c1aba9f4c8405 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts @@ -93,12 +93,12 @@ const tests: CompilerTestCases = { `, }, { - // TODO(gsn): Move this to invalid test suite, when we turn on - // validateRefAccessDuringRender validation + // Don't report the issue if Flow already has name: '[InvalidInput] Ref access during render', code: normalizeIndent` function Component(props) { const ref = useRef(null); + // $FlowFixMe[react-rule-unsafe-ref] const value = ref.current; return value; } @@ -106,6 +106,22 @@ const tests: CompilerTestCases = { }, ], invalid: [ + { + name: '[InvalidInput] Ref access during render', + code: normalizeIndent` + function Component(props) { + const ref = useRef(null); + const value = ref.current; + return value; + } + `, + errors: [ + { + message: + 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', + }, + ], + }, { name: 'Reportable levels can be configured', options: [{reportableLevels: new Set([ErrorSeverity.Todo])}], diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index 2fe34a0b7ff2b..7b6525842c4d2 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -179,7 +179,10 @@ const rule: Rule.RuleModule = { if (!isReportableDiagnostic(detail)) { return; } - if (hasFlowSuppression(detail.loc, 'react-rule-hook')) { + if ( + hasFlowSuppression(detail.loc, 'react-rule-hook') || + hasFlowSuppression(detail.loc, 'react-rule-unsafe-ref') + ) { // If Flow already caught this error, we don't need to report it again. return; } From 1eaccd8285f0bd40407705a9356391a171adf3b1 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Fri, 16 Aug 2024 21:08:20 +0200 Subject: [PATCH 008/426] [Fax] Make `react-markup` publishable via scripts (#30722) --- ReactVersions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactVersions.js b/ReactVersions.js index 736d6c8f54717..731f5f336270e 100644 --- a/ReactVersions.js +++ b/ReactVersions.js @@ -52,7 +52,7 @@ const stablePackages = { // These packages do not exist in the @canary or @latest channel, only // @experimental. We don't use semver, just the commit sha, so this is just a // list of package names instead of a map. -const experimentalPackages = []; +const experimentalPackages = ['react-markup']; module.exports = { ReactVersion, From 7b41cdc093c7a28a089e2c402cbe98cac68de509 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 16 Aug 2024 14:21:57 -0700 Subject: [PATCH 009/426] [Flight][Static] Implement halting a prerender behind enableHalt (#30705) enableHalt turns on a mode for flight prerenders where aborts are treated like infinitely stalled outcomes while still completing the prerender. For regular tasks we simply serialize the slot as a promise that never settles. For ReadableStream, Blob, and Async Iterators we just never advance the serialization so they remain unfinished when consumed on the client. When enableHalt is turned on aborts of prerenders will halt rather than error. The abort reason is forwarded to the upstream produces of the aforementioned async iterators, blobs, and ReadableStreams. In the future if we expose a signal that you can consume from within a render to cancel additional work the abort reason will also be forwarded there --- .../src/server/ReactFlightDOMServerNode.js | 17 +- .../src/server/ReactFlightDOMServerBrowser.js | 17 +- .../src/server/ReactFlightDOMServerEdge.js | 17 +- .../src/server/ReactFlightDOMServerNode.js | 17 +- .../src/__tests__/ReactFlightDOM-test.js | 134 +++++++ .../__tests__/ReactFlightDOMBrowser-test.js | 115 +++++- .../src/__tests__/ReactFlightDOMEdge-test.js | 341 +++++++++++++----- .../src/__tests__/ReactFlightDOMNode-test.js | 133 +++++++ .../src/server/ReactFlightDOMServerBrowser.js | 17 +- .../src/server/ReactFlightDOMServerEdge.js | 17 +- .../src/server/ReactFlightDOMServerNode.js | 17 +- .../react-server/src/ReactFlightServer.js | 124 +++++-- packages/shared/ReactFeatureFlags.js | 2 + .../forks/ReactFeatureFlags.native-fb.js | 1 + .../forks/ReactFeatureFlags.native-oss.js | 1 + .../forks/ReactFeatureFlags.test-renderer.js | 1 + ...actFeatureFlags.test-renderer.native-fb.js | 1 + .../ReactFeatureFlags.test-renderer.www.js | 1 + .../shared/forks/ReactFeatureFlags.www.js | 2 + 19 files changed, 855 insertions(+), 120 deletions(-) diff --git a/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js b/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js index bb65ef4b659a7..1434d17015a54 100644 --- a/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js @@ -20,12 +20,15 @@ import type {Thenable} from 'shared/ReactTypes'; import {Readable} from 'stream'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -187,10 +190,20 @@ function prerenderToNodeStream( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js index ef980764942d7..56c3d5b71f432 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js @@ -12,12 +12,15 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigTurbopackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -146,10 +149,20 @@ function prerender( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js index ef980764942d7..56c3d5b71f432 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js @@ -12,12 +12,15 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigTurbopackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -146,10 +149,20 @@ function prerender( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js index e484d4b7e77d5..f9b0c163b2154 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js @@ -20,12 +20,15 @@ import type {Thenable} from 'shared/ReactTypes'; import {Readable} from 'stream'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -189,10 +192,20 @@ function prerenderToNodeStream( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index faaf8aef01b0d..6a0ce0152b704 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -2722,4 +2722,138 @@ describe('ReactFlightDOM', () => { await readInto(container, fizzReadable); expect(getMeaningfulChildren(container)).toEqual(
hello world
); }); + + // @gate enableHalt + it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ + + +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const controller = new AbortController(); + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( + , + webpackMap, + { + signal: controller.signal, + }, + ), + }; + }); + + controller.abort(); + resolveGreeting(); + const {prelude} = await pendingResult; + + const preludeWeb = Readable.toWeb(prelude); + const response = ReactServerDOMClient.createFromReadableStream(preludeWeb); + + const {writable: fizzWritable, readable: fizzReadable} = getTestStream(); + + function ClientApp() { + return use(response); + } + + const errors = []; + let abortFizz; + await serverAct(async () => { + const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream( + React.createElement(ClientApp), + { + onError(error) { + errors.push(error); + }, + }, + ); + pipe(fizzWritable); + abortFizz = abort; + }); + + await serverAct(() => { + abortFizz('boom'); + }); + + expect(errors).toEqual(['boom']); + + const container = document.createElement('div'); + await readInto(container, fizzReadable); + expect(getMeaningfulChildren(container)).toEqual(
loading...
); + }); + + // @gate enableHalt + it('will leave async iterables in an incomplete state when halting', async () => { + let resolve; + const wait = new Promise(r => (resolve = r)); + const errors = []; + + const multiShotIterable = { + async *[Symbol.asyncIterator]() { + yield {hello: 'A'}; + await wait; + yield {hi: 'B'}; + return 'C'; + }, + }; + + const controller = new AbortController(); + const {pendingResult} = await serverAct(() => { + return { + pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( + { + multiShotIterable, + }, + {}, + { + onError(x) { + errors.push(x); + }, + signal: controller.signal, + }, + ), + }; + }); + + controller.abort(); + await serverAct(() => resolve()); + + const {prelude} = await pendingResult; + + const result = await ReactServerDOMClient.createFromReadableStream( + Readable.toWeb(prelude), + ); + + const iterator = result.multiShotIterable[Symbol.asyncIterator](); + + expect(await iterator.next()).toEqual({ + value: {hello: 'A'}, + done: false, + }); + + const race = Promise.race([ + iterator.next(), + new Promise(r => setTimeout(() => r('timeout'), 10)), + ]); + + await 1; + jest.advanceTimersByTime('100'); + expect(await race).toBe('timeout'); + }); }); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index db8edf7ad6831..7bbfea1484bed 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -29,6 +29,7 @@ let ReactDOM; let ReactDOMClient; let ReactDOMFizzServer; let ReactServerDOMServer; +let ReactServerDOMStaticServer; let ReactServerDOMClient; let Suspense; let use; @@ -60,7 +61,13 @@ describe('ReactFlightDOMBrowser', () => { serverExports = WebpackMock.serverExports; webpackMap = WebpackMock.webpackMap; webpackServerMap = WebpackMock.webpackServerMap; - ReactServerDOMServer = require('react-server-dom-webpack/server.browser'); + ReactServerDOMServer = require('react-server-dom-webpack/server'); + if (__EXPERIMENTAL__) { + jest.mock('react-server-dom-webpack/static', () => + require('react-server-dom-webpack/static.browser'), + ); + ReactServerDOMStaticServer = require('react-server-dom-webpack/static'); + } __unmockReact(); jest.resetModules(); @@ -2332,4 +2339,110 @@ describe('ReactFlightDOMBrowser', () => { expect(error.digest).toBe('aborted'); expect(errors).toEqual([reason]); }); + + // @gate experimental + it('can prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerender( + , + webpackMap, + ), + }; + }); + + resolveGreeting(); + const {prelude} = await pendingResult; + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromReadableStream( + passThrough(prelude), + ); + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(); + }); + expect(container.innerHTML).toBe('
hello world
'); + }); + + // @gate enableHalt + it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ + + +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const controller = new AbortController(); + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerender( + , + webpackMap, + { + signal: controller.signal, + }, + ), + }; + }); + + controller.abort(); + resolveGreeting(); + const {prelude} = await pendingResult; + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromReadableStream( + passThrough(prelude), + ); + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(); + }); + + expect(container.innerHTML).toBe('
loading...
'); + }); }); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index ffef621e9761b..b38c33dc7761b 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -23,9 +23,9 @@ if (typeof File === 'undefined' || typeof FormData === 'undefined') { // Patch for Edge environments for global scope global.AsyncLocalStorage = require('async_hooks').AsyncLocalStorage; -// Don't wait before processing work on the server. -// TODO: we can replace this with FlightServer.act(). -global.setTimeout = cb => cb(); +const { + patchMessageChannel, +} = require('../../../../scripts/jest/patchMessageChannel'); let serverExports; let clientExports; @@ -36,8 +36,11 @@ let React; let ReactServer; let ReactDOMServer; let ReactServerDOMServer; +let ReactServerDOMStaticServer; let ReactServerDOMClient; let use; +let ReactServerScheduler; +let reactServerAct; function normalizeCodeLocInfo(str) { return ( @@ -52,6 +55,10 @@ describe('ReactFlightDOMEdge', () => { beforeEach(() => { jest.resetModules(); + ReactServerScheduler = require('scheduler'); + patchMessageChannel(ReactServerScheduler); + reactServerAct = require('internal-test-utils').act; + // Simulate the condition resolution jest.mock('react', () => require('react/react.react-server')); jest.mock('react-server-dom-webpack/server', () => @@ -68,6 +75,12 @@ describe('ReactFlightDOMEdge', () => { ReactServer = require('react'); ReactServerDOMServer = require('react-server-dom-webpack/server'); + if (__EXPERIMENTAL__) { + jest.mock('react-server-dom-webpack/static', () => + require('react-server-dom-webpack/static.edge'), + ); + ReactServerDOMStaticServer = require('react-server-dom-webpack/static'); + } jest.resetModules(); __unmockReact(); @@ -81,6 +94,17 @@ describe('ReactFlightDOMEdge', () => { use = React.use; }); + async function serverAct(callback) { + let maybePromise; + await reactServerAct(() => { + maybePromise = callback(); + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(() => {}); + } + }); + return maybePromise; + } + function passThrough(stream) { // Simulate more realistic network by splitting up and rejoining some chunks. // This lets us test that we don't accidentally rely on particular bounds of the chunks. @@ -174,9 +198,8 @@ describe('ReactFlightDOMEdge', () => { return ; } - const stream = ReactServerDOMServer.renderToReadableStream( - , - webpackMap, + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(, webpackMap), ); const response = ReactServerDOMClient.createFromReadableStream(stream, { ssrManifest: { @@ -189,8 +212,8 @@ describe('ReactFlightDOMEdge', () => { return use(response); } - const ssrStream = await ReactDOMServer.renderToReadableStream( - , + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(), ); const result = await readResult(ssrStream); expect(result).toEqual('Client Component'); @@ -200,10 +223,12 @@ describe('ReactFlightDOMEdge', () => { const testString = '"\n\t'.repeat(500) + '🙃'; const testString2 = 'hello'.repeat(400); - const stream = ReactServerDOMServer.renderToReadableStream({ - text: testString, - text2: testString2, - }); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream({ + text: testString, + text2: testString2, + }), + ); const [stream1, stream2] = passThrough(stream).tee(); const serializedContent = await readResult(stream1); @@ -234,7 +259,9 @@ describe('ReactFlightDOMEdge', () => { with: {many: 'properties in it'}, }; const props = {root:
{new Array(30).fill(obj)}
}; - const stream = ReactServerDOMServer.renderToReadableStream(props); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(props), + ); const [stream1, stream2] = passThrough(stream).tee(); const serializedContent = await readResult(stream1); @@ -302,7 +329,9 @@ describe('ReactFlightDOMEdge', () => { ); const resolvedChildren = new Array(30).fill(str); - const stream = ReactServerDOMServer.renderToReadableStream(children); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(children), + ); const [stream1, stream2] = passThrough(stream).tee(); const serializedContent = await readResult(stream1); @@ -318,7 +347,9 @@ describe('ReactFlightDOMEdge', () => { }); // Use the SSR render to resolve any lazy elements - const ssrStream = await ReactDOMServer.renderToReadableStream(model); + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(model), + ); // Should still match the result when parsed const result = await readResult(ssrStream); expect(result).toEqual(resolvedChildren.join('')); @@ -370,22 +401,28 @@ describe('ReactFlightDOMEdge', () => { const resolvedChildren = new Array(30).fill( '
this is a long return value
', ); - const stream = ReactServerDOMServer.renderToReadableStream(children); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(children), + ); const [stream1, stream2] = passThrough(stream).tee(); const serializedContent = await readResult(stream1); expect(serializedContent.length).toBeLessThan(__DEV__ ? 605 : 400); expect(timesRendered).toBeLessThan(5); - const model = await ReactServerDOMClient.createFromReadableStream(stream2, { - ssrManifest: { - moduleMap: null, - moduleLoading: null, - }, - }); + const model = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream2, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }), + ); // Use the SSR render to resolve any lazy elements - const ssrStream = await ReactDOMServer.renderToReadableStream(model); + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(model), + ); // Should still match the result when parsed const result = await readResult(ssrStream); expect(result).toEqual(resolvedChildren.join('')); @@ -398,8 +435,10 @@ describe('ReactFlightDOMEdge', () => { } return
Fin
; } - const stream = ReactServerDOMServer.renderToReadableStream( - , + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream( + , + ), ); const serializedContent = await readResult(stream); const expectedDebugInfoSize = __DEV__ ? 300 * 20 : 0; @@ -426,8 +465,8 @@ describe('ReactFlightDOMEdge', () => { new BigUint64Array(buffer, 0), new DataView(buffer, 3), ]; - const stream = passThrough( - ReactServerDOMServer.renderToReadableStream(buffers), + const stream = await serverAct(() => + passThrough(ReactServerDOMServer.renderToReadableStream(buffers)), ); const result = await ReactServerDOMClient.createFromReadableStream(stream, { ssrManifest: { @@ -446,8 +485,8 @@ describe('ReactFlightDOMEdge', () => { const blob = new Blob([bytes, bytes], { type: 'application/x-test', }); - const stream = passThrough( - ReactServerDOMServer.renderToReadableStream(blob), + const stream = await serverAct(() => + passThrough(ReactServerDOMServer.renderToReadableStream(blob)), ); const result = await ReactServerDOMClient.createFromReadableStream(stream, { ssrManifest: { @@ -476,8 +515,8 @@ describe('ReactFlightDOMEdge', () => { expect(formData.get('file') instanceof File).toBe(true); expect(formData.get('file').name).toBe('filename.test'); - const stream = passThrough( - ReactServerDOMServer.renderToReadableStream(formData), + const stream = await serverAct(() => + passThrough(ReactServerDOMServer.renderToReadableStream(formData)), ); const result = await ReactServerDOMClient.createFromReadableStream(stream, { ssrManifest: { @@ -507,8 +546,8 @@ describe('ReactFlightDOMEdge', () => { const map = new Map(); map.set('value', awaitedValue); - const stream = passThrough( - ReactServerDOMServer.renderToReadableStream(map, webpackMap), + const stream = await serverAct(() => + passThrough(ReactServerDOMServer.renderToReadableStream(map, webpackMap)), ); // Parsing the root blocks because the module hasn't loaded yet @@ -549,16 +588,18 @@ describe('ReactFlightDOMEdge', () => { }, }); - const stream = passThrough( - ReactServerDOMServer.renderToReadableStream(s, webpackMap), + const stream = await serverAct(() => + passThrough(ReactServerDOMServer.renderToReadableStream(s, webpackMap)), ); - const result = await ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { - moduleMap: null, - moduleLoading: null, - }, - }); + const result = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }), + ); const reader = result.getReader(); @@ -589,20 +630,24 @@ describe('ReactFlightDOMEdge', () => { }, }; - const stream = passThrough( - ReactServerDOMServer.renderToReadableStream( - multiShotIterable, - webpackMap, + const stream = await serverAct(() => + passThrough( + ReactServerDOMServer.renderToReadableStream( + multiShotIterable, + webpackMap, + ), ), ); // Parsing the root blocks because the module hasn't loaded yet - const result = await ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { - moduleMap: null, - moduleLoading: null, - }, - }); + const result = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }), + ); const iterator = result[Symbol.asyncIterator](); @@ -635,9 +680,11 @@ describe('ReactFlightDOMEdge', () => { }, }; - const stream = ReactServerDOMServer.renderToReadableStream({ - iterable, - }); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream({ + iterable, + }), + ); const [stream1, stream2] = passThrough(stream).tee(); const serializedContent = await readResult(stream1); @@ -728,7 +775,9 @@ describe('ReactFlightDOMEdge', () => { }, }); - const stream = ReactServerDOMServer.renderToReadableStream(s, {}); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(s, {}), + ); const [stream1, stream2] = passThrough(stream).tee(); @@ -785,7 +834,9 @@ describe('ReactFlightDOMEdge', () => { }, }); - const stream = ReactServerDOMServer.renderToReadableStream(s, {}); + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(s, {}), + ); const [stream1, stream2] = passThrough(stream).tee(); @@ -841,23 +892,21 @@ describe('ReactFlightDOMEdge', () => { greeting: ReactServer.createElement(Greeting, {firstName: 'Seb'}), }; - const stream = ReactServerDOMServer.renderToReadableStream( - model, - webpackMap, + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(model, webpackMap), ); - const rootModel = await ReactServerDOMClient.createFromReadableStream( - stream, - { + const rootModel = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream, { ssrManifest: { moduleMap: null, moduleLoading: null, }, - }, + }), ); - const ssrStream = await ReactDOMServer.renderToReadableStream( - rootModel.greeting, + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream(rootModel.greeting), ); const result = await readResult(ssrStream); expect(result).toEqual('Hello, Seb'); @@ -916,13 +965,15 @@ describe('ReactFlightDOMEdge', () => { return ReactServer.createElement('span', null, 'hi'); } - const stream = ReactServerDOMServer.renderToReadableStream( - ReactServer.createElement( - 'div', - null, - ReactServer.createElement(Foo, null), + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream( + ReactServer.createElement( + 'div', + null, + ReactServer.createElement(Foo, null), + ), + webpackMap, ), - webpackMap, ); await readResult(stream); @@ -943,35 +994,31 @@ describe('ReactFlightDOMEdge', () => { root: ReactServer.createElement(Erroring), }; - const stream = ReactServerDOMServer.renderToReadableStream( - model, - webpackMap, - { + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(model, webpackMap, { onError() {}, - }, + }), ); - const rootModel = await ReactServerDOMClient.createFromReadableStream( - stream, - { + const rootModel = await serverAct(() => + ReactServerDOMClient.createFromReadableStream(stream, { ssrManifest: { moduleMap: null, moduleLoading: null, }, - }, + }), ); const errors = []; - const result = ReactDOMServer.renderToReadableStream( -
{rootModel.root}
, - { + const result = serverAct(() => + ReactDOMServer.renderToReadableStream(
{rootModel.root}
, { onError(error, {componentStack}) { errors.push({ error, componentStack: normalizeCodeLocInfo(componentStack), }); }, - }, + }), ); const theError = new Error('my error'); @@ -1000,4 +1047,130 @@ describe('ReactFlightDOMEdge', () => { }, ]); }); + + // @gate experimental + it('can prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerender( + , + webpackMap, + ), + }; + }); + + resolveGreeting(); + const {prelude} = await pendingResult; + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromReadableStream(prelude, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }); + // Use the SSR render to resolve any lazy elements + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream( + React.createElement(ClientRoot, {response}), + ), + ); + // Should still match the result when parsed + const result = await readResult(ssrStream); + expect(result).toBe('
hello world
'); + }); + + // @gate enableHalt + it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ + + +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const controller = new AbortController(); + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerender( + , + webpackMap, + { + signal: controller.signal, + }, + ), + }; + }); + + controller.abort(); + resolveGreeting(); + const {prelude} = await pendingResult; + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromReadableStream(prelude, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }); + const fizzController = new AbortController(); + const errors = []; + const ssrStream = await serverAct(() => + ReactDOMServer.renderToReadableStream( + React.createElement(ClientRoot, {response}), + { + signal: fizzController.signal, + onError(error) { + errors.push(error); + }, + }, + ), + ); + fizzController.abort('boom'); + expect(errors).toEqual(['boom']); + // Should still match the result when parsed + const result = await readResult(ssrStream); + const div = document.createElement('div'); + div.innerHTML = result; + expect(div.textContent).toBe('loading...'); + }); }); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js index 2de34cc1c493f..fbe32d2f1f697 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js @@ -20,7 +20,9 @@ let webpackModules; let webpackModuleLoading; let React; let ReactDOMServer; +let ReactServer; let ReactServerDOMServer; +let ReactServerDOMStaticServer; let ReactServerDOMClient; let Stream; let use; @@ -45,7 +47,14 @@ describe('ReactFlightDOMNode', () => { jest.mock('react-server-dom-webpack/server', () => require('react-server-dom-webpack/server.node'), ); + ReactServer = require('react'); ReactServerDOMServer = require('react-server-dom-webpack/server'); + if (__EXPERIMENTAL__) { + jest.mock('react-server-dom-webpack/static', () => + require('react-server-dom-webpack/static.node'), + ); + ReactServerDOMStaticServer = require('react-server-dom-webpack/static'); + } const WebpackMock = require('./utils/WebpackMock'); clientExports = WebpackMock.clientExports; @@ -378,4 +387,128 @@ describe('ReactFlightDOMNode', () => { expect(error.digest).toBe('aborted'); expect(errors).toEqual([reason]); }); + + // @gate experimental + it('can prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( + , + webpackMap, + ), + }; + }); + + resolveGreeting(); + const {prelude} = await pendingResult; + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromNodeStream(prelude, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }); + // Use the SSR render to resolve any lazy elements + const ssrStream = await serverAct(() => + ReactDOMServer.renderToPipeableStream( + React.createElement(ClientRoot, {response}), + ), + ); + // Should still match the result when parsed + const result = await readResult(ssrStream); + expect(result).toBe('
hello world
'); + }); + + // @gate enableHalt + it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + let resolveGreeting; + const greetingPromise = new Promise(resolve => { + resolveGreeting = resolve; + }); + + function App() { + return ( +
+ + + +
+ ); + } + + async function Greeting() { + await greetingPromise; + return 'hello world'; + } + + const controller = new AbortController(); + const {pendingResult} = await serverAct(async () => { + // destructure trick to avoid the act scope from awaiting the returned value + return { + pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( + , + webpackMap, + { + signal: controller.signal, + }, + ), + }; + }); + + controller.abort(); + resolveGreeting(); + const {prelude} = await pendingResult; + + function ClientRoot({response}) { + return use(response); + } + + const response = ReactServerDOMClient.createFromNodeStream(prelude, { + ssrManifest: { + moduleMap: null, + moduleLoading: null, + }, + }); + const errors = []; + const ssrStream = await serverAct(() => + ReactDOMServer.renderToPipeableStream( + React.createElement(ClientRoot, {response}), + { + onError(error) { + errors.push(error); + }, + }, + ), + ); + ssrStream.abort('boom'); + expect(errors).toEqual(['boom']); + // Should still match the result when parsed + const result = await readResult(ssrStream); + const div = document.createElement('div'); + div.innerHTML = result; + expect(div.textContent).toBe('loading...'); + }); }); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js index a4e0c3bef693b..95e7f770428a3 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js @@ -12,12 +12,15 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigWebpackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -146,10 +149,20 @@ function prerender( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js index a4e0c3bef693b..95e7f770428a3 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js @@ -12,12 +12,15 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigWebpackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -146,10 +149,20 @@ function prerender( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js index 1506259476703..1d8d6ea9ef743 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js @@ -20,12 +20,15 @@ import type {Thenable} from 'shared/ReactTypes'; import {Readable} from 'stream'; +import {enableHalt} from 'shared/ReactFeatureFlags'; + import { createRequest, startWork, startFlowing, stopFlowing, abort, + halt, } from 'react-server/src/ReactFlightServer'; import { @@ -189,10 +192,20 @@ function prerenderToNodeStream( if (options && options.signal) { const signal = options.signal; if (signal.aborted) { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } } else { const listener = () => { - abort(request, (signal: any).reason); + const reason = (signal: any).reason; + if (enableHalt) { + halt(request, reason); + } else { + abort(request, reason); + } signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index d8ba106d37e72..db0ee7b3cebad 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -16,6 +16,7 @@ import type {TemporaryReferenceSet} from './ReactFlightServerTemporaryReferences import { enableBinaryFlight, enablePostpone, + enableHalt, enableTaint, enableRefAsProp, enableServerComponentLogs, @@ -611,11 +612,15 @@ function serializeThenable( default: { if (request.status === ABORTING) { // We can no longer accept any resolved values - newTask.status = ABORTED; - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, newTask.id, model); request.abortableTasks.delete(newTask); + newTask.status = ABORTED; + if (enableHalt && request.fatalError === haltSymbol) { + emitModelChunk(request, newTask.id, reusableInfinitePromiseModel); + } else { + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, newTask.id, model); + } return newTask.id; } if (typeof thenable.status === 'string') { @@ -748,23 +753,32 @@ function serializeReadableStream( } aborted = true; request.abortListeners.delete(error); - if ( + + let cancelWith: mixed; + if (enableHalt && request.fatalError === haltSymbol) { + cancelWith = reason; + } else if ( enablePostpone && typeof reason === 'object' && reason !== null && (reason: any).$$typeof === REACT_POSTPONE_TYPE ) { + cancelWith = reason; const postponeInstance: Postpone = (reason: any); logPostpone(request, postponeInstance.message, streamTask); emitPostponeChunk(request, streamTask.id, postponeInstance); + enqueueFlush(request); } else { + cancelWith = reason; const digest = logRecoverableError(request, reason, streamTask); emitErrorChunk(request, streamTask.id, digest, reason); + enqueueFlush(request); } - enqueueFlush(request); + // $FlowFixMe should be able to pass mixed - reader.cancel(reason).then(error, error); + reader.cancel(cancelWith).then(error, error); } + request.abortListeners.add(error); reader.read().then(progress, error); return serializeByValueID(streamTask.id); @@ -866,24 +880,30 @@ function serializeAsyncIterable( } aborted = true; request.abortListeners.delete(error); - if ( + let throwWith: mixed; + if (enableHalt && request.fatalError === haltSymbol) { + throwWith = reason; + } else if ( enablePostpone && typeof reason === 'object' && reason !== null && (reason: any).$$typeof === REACT_POSTPONE_TYPE ) { + throwWith = reason; const postponeInstance: Postpone = (reason: any); logPostpone(request, postponeInstance.message, streamTask); emitPostponeChunk(request, streamTask.id, postponeInstance); + enqueueFlush(request); } else { + throwWith = reason; const digest = logRecoverableError(request, reason, streamTask); emitErrorChunk(request, streamTask.id, digest, reason); + enqueueFlush(request); } - enqueueFlush(request); if (typeof (iterator: any).throw === 'function') { // The iterator protocol doesn't necessarily include this but a generator do. // $FlowFixMe should be able to pass mixed - iterator.throw(reason).then(error, error); + iterator.throw(throwWith).then(error, error); } } request.abortListeners.add(error); @@ -1798,6 +1818,7 @@ function serializeLazyID(id: number): string { function serializeInfinitePromise(): string { return '$@'; } +const reusableInfinitePromiseModel = stringify(serializeInfinitePromise()); function serializePromiseID(id: number): string { return '$@' + id.toString(16); @@ -2066,12 +2087,18 @@ function serializeBlob(request: Request, blob: Blob): string { } aborted = true; request.abortListeners.delete(error); - const digest = logRecoverableError(request, reason, newTask); - emitErrorChunk(request, newTask.id, digest, reason); - request.abortableTasks.delete(newTask); - enqueueFlush(request); + let cancelWith: mixed; + if (enableHalt && request.fatalError === haltSymbol) { + cancelWith = reason; + } else { + cancelWith = reason; + const digest = logRecoverableError(request, reason, newTask); + emitErrorChunk(request, newTask.id, digest, reason); + request.abortableTasks.delete(newTask); + enqueueFlush(request); + } // $FlowFixMe should be able to pass mixed - reader.cancel(reason).then(error, error); + reader.cancel(cancelWith).then(error, error); } request.abortListeners.add(error); @@ -2149,6 +2176,9 @@ function renderModel( if (typeof x.then === 'function') { if (request.status === ABORTING) { task.status = ABORTED; + if (enableHalt && request.fatalError === haltSymbol) { + return serializeInfinitePromise(); + } const errorId: number = (request.fatalError: any); if (wasReactNode) { return serializeLazyID(errorId); @@ -2202,6 +2232,9 @@ function renderModel( if (request.status === ABORTING) { task.status = ABORTED; + if (enableHalt && request.fatalError === haltSymbol) { + return serializeInfinitePromise(); + } const errorId: number = (request.fatalError: any); if (wasReactNode) { return serializeLazyID(errorId); @@ -3691,9 +3724,13 @@ function retryTask(request: Request, task: Task): void { if (request.status === ABORTING) { request.abortableTasks.delete(task); task.status = ABORTED; - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, task.id, model); + if (enableHalt && request.fatalError === haltSymbol) { + emitModelChunk(request, task.id, reusableInfinitePromiseModel); + } else { + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, task.id, model); + } return; } // Something suspended again, let's pick it back up later. @@ -3715,9 +3752,13 @@ function retryTask(request: Request, task: Task): void { if (request.status === ABORTING) { request.abortableTasks.delete(task); task.status = ABORTED; - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, task.id, model); + if (enableHalt && request.fatalError === haltSymbol) { + emitModelChunk(request, task.id, reusableInfinitePromiseModel); + } else { + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, task.id, model); + } return; } @@ -3795,6 +3836,15 @@ function abortTask(task: Task, request: Request, errorId: number): void { request.completedErrorChunks.push(processedChunk); } +function haltTask(task: Task, request: Request): void { + if (task.status === RENDERING) { + // This task will be aborted by the render + return; + } + task.status = ABORTED; + emitModelChunk(request, task.id, reusableInfinitePromiseModel); +} + function flushCompletedChunks( request: Request, destination: Destination, @@ -4012,3 +4062,35 @@ export function abort(request: Request, reason: mixed): void { fatalError(request, error); } } + +const haltSymbol = Symbol('halt'); + +// This is called to stop rendering without erroring. All unfinished work is represented Promises +// that never resolve. +export function halt(request: Request, reason: mixed): void { + try { + if (request.status === OPEN) { + request.status = ABORTING; + } + request.fatalError = haltSymbol; + const abortableTasks = request.abortableTasks; + // We have tasks to abort. We'll emit one error row and then emit a reference + // to that row from every row that's still remaining. + if (abortableTasks.size > 0) { + request.pendingChunks++; + abortableTasks.forEach(task => haltTask(task, request)); + abortableTasks.clear(); + } + const abortListeners = request.abortListeners; + if (abortListeners.size > 0) { + abortListeners.forEach(callback => callback(reason)); + abortListeners.clear(); + } + if (request.destination !== null) { + flushCompletedChunks(request, request.destination); + } + } catch (error) { + logRecoverableError(request, error, null); + fatalError(request, error); + } +} diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index b0286405a6cca..c5351d6d92631 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -87,6 +87,8 @@ export const enableTaint = __EXPERIMENTAL__; export const enablePostpone = __EXPERIMENTAL__; +export const enableHalt = __EXPERIMENTAL__; + /** * Switches the Fabric API from doing layout in commit work instead of complete work. */ diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 4eda27d16cfcb..3618aa70e7d67 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -58,6 +58,7 @@ export const enableFilterEmptyStringAttributesDOM = true; export const enableFizzExternalRuntime = true; export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = true; +export const enableHalt = false; export const enableInfiniteRenderLoopDetection = true; export const enableContextProfiling = false; export const enableLegacyCache = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 2a4421f41da0a..2aae8bd3d1c65 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -49,6 +49,7 @@ export const enableFilterEmptyStringAttributesDOM = true; export const enableFizzExternalRuntime = true; export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = false; +export const enableHalt = false; export const enableInfiniteRenderLoopDetection = true; export const enableLazyContextPropagation = false; export const enableContextProfiling = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 8778bf6558cb4..c44e7014fc444 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -25,6 +25,7 @@ export const enableFlightReadableStream = true; export const enableAsyncIterableChildren = false; export const enableTaint = true; export const enablePostpone = false; +export const enableHalt = false; export const disableCommentsAsDOMContainers = true; export const disableInputAttributeSyncing = false; export const disableIEWorkarounds = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 3a8a0c1d44cec..bc7ddf85acc03 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -40,6 +40,7 @@ export const enableFilterEmptyStringAttributesDOM = true; export const enableFizzExternalRuntime = true; export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = false; +export const enableHalt = false; export const enableInfiniteRenderLoopDetection = true; export const enableLazyContextPropagation = false; export const enableContextProfiling = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index eb801d7bac4b6..57f60c24aef45 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -25,6 +25,7 @@ export const enableFlightReadableStream = true; export const enableAsyncIterableChildren = false; export const enableTaint = true; export const enablePostpone = false; +export const enableHalt = false; export const disableCommentsAsDOMContainers = true; export const disableInputAttributeSyncing = false; export const disableIEWorkarounds = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 95cd1e5a6ebe6..465fa58590bcc 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -78,6 +78,8 @@ export const enableTaint = false; export const enablePostpone = false; +export const enableHalt = false; + export const enableContextProfiling = true; // TODO: www currently relies on this feature. It's disabled in open source. From e9a869fbb59a634fb9a39c9480ffa34970f35858 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 16 Aug 2024 17:39:50 -0400 Subject: [PATCH 010/426] [compiler] Run compiler pipeline on 'use no forget' This PR updates the babel plugin to continue the compilation pipeline as normal on components/hooks that have been opted out using a directive. Instead, we no longer emit the compiled function when the directive is present. Previously, we would skip over the entire pipeline. By continuing to enter the pipeline, we'll be able to detect if there are unused directives. The end result is: - (no change) 'use forget' will always opt into compilation - (new) 'use no forget' will opt out of compilation but continue to log errors without throwing them. This means that a Program containing multiple functions (some of which are opted out) will continue to compile correctly ghstack-source-id: 5bd85df2f81350cb2c1998a8761b8ed3fec32a40 Pull Request resolved: https://github.com/facebook/react/pull/30720 --- .../src/Entrypoint/Options.ts | 6 + .../src/Entrypoint/Program.ts | 146 ++++++++++-------- .../use-no-forget-with-no-errors.expect.md | 35 +++++ .../compiler/use-no-forget-with-no-errors.js | 10 ++ .../babel-plugin-react-compiler/src/index.ts | 1 + 5 files changed, 136 insertions(+), 62 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index 722c62461d813..e97ececc2a137 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -165,6 +165,12 @@ export type LoggerEvent = fnLoc: t.SourceLocation | null; detail: Omit, 'suggestions'>; } + | { + kind: 'CompileSkip'; + fnLoc: t.SourceLocation | null; + reason: string; + loc: t.SourceLocation | null; + } | { kind: 'CompileSuccess'; fnLoc: t.SourceLocation | null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 499a4d124ea67..99ec1e04a65e4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -43,34 +43,23 @@ export type CompilerPass = { comments: Array; code: string | null; }; +const OPT_IN_DIRECTIVES = new Set(['use forget', 'use memo']); +export const OPT_OUT_DIRECTIVES = new Set(['use no forget', 'use no memo']); function findDirectiveEnablingMemoization( directives: Array, -): t.Directive | null { - for (const directive of directives) { - const directiveValue = directive.value.value; - if (directiveValue === 'use forget' || directiveValue === 'use memo') { - return directive; - } - } - return null; +): Array { + return directives.filter(directive => + OPT_IN_DIRECTIVES.has(directive.value.value), + ); } function findDirectiveDisablingMemoization( directives: Array, - options: PluginOptions, -): t.Directive | null { - for (const directive of directives) { - const directiveValue = directive.value.value; - if ( - (directiveValue === 'use no forget' || - directiveValue === 'use no memo') && - !options.ignoreUseNoForget - ) { - return directive; - } - } - return null; +): Array { + return directives.filter(directive => + OPT_OUT_DIRECTIVES.has(directive.value.value), + ); } function isCriticalError(err: unknown): boolean { @@ -102,7 +91,7 @@ export type CompileResult = { compiledFn: CodegenFunction; }; -function handleError( +function logError( err: unknown, pass: CompilerPass, fnLoc: t.SourceLocation | null, @@ -131,6 +120,13 @@ function handleError( }); } } +} +function handleError( + err: unknown, + pass: CompilerPass, + fnLoc: t.SourceLocation | null, +): void { + logError(err, pass, fnLoc); if ( pass.opts.panicThreshold === 'all_errors' || (pass.opts.panicThreshold === 'critical_errors' && isCriticalError(err)) || @@ -393,6 +389,17 @@ export function compileProgram( fn: BabelFn, fnType: ReactFunctionType, ): null | CodegenFunction => { + let optInDirectives: Array = []; + let optOutDirectives: Array = []; + if (fn.node.body.type === 'BlockStatement') { + optInDirectives = findDirectiveEnablingMemoization( + fn.node.body.directives, + ); + optOutDirectives = findDirectiveDisablingMemoization( + fn.node.body.directives, + ); + } + if (lintError != null) { /** * Note that Babel does not attach comment nodes to nodes; they are dangling off of the @@ -404,7 +411,11 @@ export function compileProgram( fn, ); if (suppressionsInFunction.length > 0) { - handleError(lintError, pass, fn.node.loc ?? null); + if (optOutDirectives.length > 0) { + logError(lintError, pass, fn.node.loc ?? null); + } else { + handleError(lintError, pass, fn.node.loc ?? null); + } } } @@ -430,11 +441,50 @@ export function compileProgram( prunedMemoValues: compiledFn.prunedMemoValues, }); } catch (err) { + /** + * If an opt out directive is present, log only instead of throwing and don't mark as + * containing a critical error. + */ + if (fn.node.body.type === 'BlockStatement') { + if (optOutDirectives.length > 0) { + logError(err, pass, fn.node.loc ?? null); + return null; + } + } hasCriticalError ||= isCriticalError(err); handleError(err, pass, fn.node.loc ?? null); return null; } + /** + * Always compile functions with opt in directives. + */ + if (optInDirectives.length > 0) { + return compiledFn; + } else if (pass.opts.compilationMode === 'annotation') { + /** + * No opt-in directive in annotation mode, so don't insert the compiled function. + */ + return null; + } + + /** + * Otherwise if 'use no forget/memo' is present, we still run the code through the compiler + * for validation but we don't mutate the babel AST. This allows us to flag if there is an + * unused 'use no forget/memo' directive. + */ + if (pass.opts.ignoreUseNoForget === false && optOutDirectives.length > 0) { + for (const directive of optOutDirectives) { + pass.opts.logger?.logEvent(pass.filename, { + kind: 'CompileSkip', + fnLoc: fn.node.body.loc ?? null, + reason: `Skipped due to '${directive.value.value}' directive.`, + loc: directive.loc ?? null, + }); + } + return null; + } + if (!pass.opts.noEmit && !hasCriticalError) { return compiledFn; } @@ -481,6 +531,16 @@ export function compileProgram( }); } + /** + * Do not modify source if there is a module scope level opt out directive. + */ + const moduleScopeOptOutDirectives = findDirectiveDisablingMemoization( + program.node.directives, + ); + if (moduleScopeOptOutDirectives.length > 0) { + return; + } + if (pass.opts.gating != null) { const error = checkFunctionReferencedBeforeDeclarationAtTopLevel( program, @@ -596,24 +656,6 @@ function shouldSkipCompilation( } } - // Top level "use no forget", skip this file entirely - const useNoForget = findDirectiveDisablingMemoization( - program.node.directives, - pass.opts, - ); - if (useNoForget != null) { - pass.opts.logger?.logEvent(pass.filename, { - kind: 'CompileError', - fnLoc: null, - detail: { - severity: ErrorSeverity.Todo, - reason: 'Skipped due to "use no forget" directive.', - loc: useNoForget.loc ?? null, - suggestions: null, - }, - }); - return true; - } const moduleName = pass.opts.runtimeModule ?? 'react/compiler-runtime'; if (hasMemoCacheFunctionImport(program, moduleName)) { return true; @@ -631,28 +673,8 @@ function getReactFunctionType( ): ReactFunctionType | null { const hookPattern = environment.hookPattern; if (fn.node.body.type === 'BlockStatement') { - // Opt-outs disable compilation regardless of mode - const useNoForget = findDirectiveDisablingMemoization( - fn.node.body.directives, - pass.opts, - ); - if (useNoForget != null) { - pass.opts.logger?.logEvent(pass.filename, { - kind: 'CompileError', - fnLoc: fn.node.body.loc ?? null, - detail: { - severity: ErrorSeverity.Todo, - reason: 'Skipped due to "use no forget" directive.', - loc: useNoForget.loc ?? null, - suggestions: null, - }, - }); - return null; - } - // Otherwise opt-ins enable compilation regardless of mode - if (findDirectiveEnablingMemoization(fn.node.body.directives) != null) { + if (findDirectiveEnablingMemoization(fn.node.body.directives).length > 0) return getComponentOrHookLike(fn, hookPattern) ?? 'Other'; - } } // Component and hook declarations are known components/hooks diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.expect.md new file mode 100644 index 0000000000000..20acbe0153135 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +function Component() { + 'use no forget'; + return
Hello World
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + isComponent: true, +}; + +``` + +## Code + +```javascript +function Component() { + "use no forget"; + return
Hello World
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + isComponent: true, +}; + +``` + +### Eval output +(kind: ok)
Hello World
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.js new file mode 100644 index 0000000000000..934487160d55c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-no-forget-with-no-errors.js @@ -0,0 +1,10 @@ +function Component() { + 'use no forget'; + return
Hello World
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + isComponent: true, +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/index.ts b/compiler/packages/babel-plugin-react-compiler/src/index.ts index f038246a4f1ee..aac65331a0ff2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/index.ts @@ -18,6 +18,7 @@ export { compileProgram, parsePluginOptions, run, + OPT_OUT_DIRECTIVES, type CompilerPipelineValue, type PluginOptions, } from './Entrypoint'; From 34edf3b68471e87d4a92f98a10f7c6c727c948f8 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 16 Aug 2024 17:39:51 -0400 Subject: [PATCH 011/426] [compiler] Surface unused opt out directives in eslint This PR updates the eslint plugin to report unused opt out directives. One of the downsides of the opt out directive is that it opts the component/hook out of compilation forever, even if the underlying issue was fixed in product code or fixed in the compiler. ghstack-source-id: 81deb5c11b7c57f07f6ab13266066cd73b2f3729 Pull Request resolved: https://github.com/facebook/react/pull/30721 --- .../__tests__/ReactCompilerRule-test.ts | 59 +++++++++++++++++++ .../src/rules/ReactCompilerRule.ts | 51 +++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts b/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts index c1aba9f4c8405..71be6b6622eb5 100644 --- a/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts +++ b/compiler/packages/eslint-plugin-react-compiler/__tests__/ReactCompilerRule-test.ts @@ -215,6 +215,65 @@ const tests: CompilerTestCases = { }, ], }, + { + name: "'use no forget' does not disable eslint rule", + code: normalizeIndent` + let count = 0; + function Component() { + 'use no forget'; + count = count + 1; + return
Hello world {count}
+ } + `, + errors: [ + { + message: + 'Unexpected reassignment of a variable which was defined outside of the component. Components and hooks should be pure and side-effect free, but variable reassignment is a form of side-effect. If this variable is used in rendering, use useState instead. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#side-effects-must-run-outside-of-render)', + }, + ], + }, + { + name: "Unused 'use no forget' directive is reported when no errors are present on components", + code: normalizeIndent` + function Component() { + 'use no forget'; + return
Hello world
+ } + `, + errors: [ + { + message: "Unused 'use no forget' directive", + suggestions: [ + { + output: + // yuck + '\nfunction Component() {\n \n return
Hello world
\n}\n', + }, + ], + }, + ], + }, + { + name: "Unused 'use no forget' directive is reported when no errors are present on non-components or hooks", + code: normalizeIndent` + function notacomponent() { + 'use no forget'; + return 1 + 1; + } + `, + errors: [ + { + message: "Unused 'use no forget' directive", + suggestions: [ + { + output: + // yuck + '\nfunction notacomponent() {\n \n return 1 + 1;\n}\n', + }, + ], + }, + ], + }, ], }; diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index 7b6525842c4d2..0a0956ebe1db0 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -15,10 +15,12 @@ import BabelPluginReactCompiler, { ErrorSeverity, parsePluginOptions, validateEnvironmentConfig, + OPT_OUT_DIRECTIVES, type PluginOptions, } from 'babel-plugin-react-compiler/src'; import {Logger} from 'babel-plugin-react-compiler/src/Entrypoint'; import type {Rule} from 'eslint'; +import {Statement} from 'estree'; import * as HermesParser from 'hermes-parser'; type CompilerErrorDetailWithLoc = Omit & { @@ -146,6 +148,7 @@ const rule: Rule.RuleModule = { userOpts['__unstable_donotuse_reportAllBailouts']; } + let shouldReportUnusedOptOutDirective = true; const options: PluginOptions = { ...parsePluginOptions(userOpts), ...COMPILER_OPTIONS, @@ -155,6 +158,7 @@ const rule: Rule.RuleModule = { logEvent: (filename, event): void => { userLogger?.logEvent(filename, event); if (event.kind === 'CompileError') { + shouldReportUnusedOptOutDirective = false; const detail = event.detail; const suggest = makeSuggestions(detail); if (__unstable_donotuse_reportAllBailouts && event.fnLoc != null) { @@ -272,7 +276,52 @@ const rule: Rule.RuleModule = { /* errors handled by injected logger */ } } - return {}; + + function reportUnusedOptOutDirective(stmt: Statement) { + if ( + stmt.type === 'ExpressionStatement' && + stmt.expression.type === 'Literal' && + typeof stmt.expression.value === 'string' && + OPT_OUT_DIRECTIVES.has(stmt.expression.value) && + stmt.loc != null + ) { + context.report({ + message: `Unused '${stmt.expression.value}' directive`, + loc: stmt.loc, + suggest: [ + { + desc: 'Remove the directive', + fix(fixer) { + return fixer.remove(stmt); + }, + }, + ], + }); + } + } + if (shouldReportUnusedOptOutDirective) { + return { + FunctionDeclaration(fnDecl) { + for (const stmt of fnDecl.body.body) { + reportUnusedOptOutDirective(stmt); + } + }, + ArrowFunctionExpression(fnExpr) { + if (fnExpr.body.type === 'BlockStatement') { + for (const stmt of fnExpr.body.body) { + reportUnusedOptOutDirective(stmt); + } + } + }, + FunctionExpression(fnExpr) { + for (const stmt of fnExpr.body.body) { + reportUnusedOptOutDirective(stmt); + } + }, + }; + } else { + return {}; + } }, }; From a58276cbc3a70ba99572eeb9c2f7b4a54ca44b1e Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 16 Aug 2024 17:39:51 -0400 Subject: [PATCH 012/426] [playground] Allow (Arrow)FunctionExpressions This was a pet peeve where our playground could only compile top level FunctionDeclarations. Just synthesize a fake identifier if it doesn't have one. ghstack-source-id: 882483c79ceebf382b69e37aed1f293efff9c5a7 Pull Request resolved: https://github.com/facebook/react/pull/30729 --- .../components/Editor/EditorImpl.tsx | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index ebac65dc4b9f2..7b1214b4600c3 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -66,14 +66,14 @@ function parseFunctions( source: string, language: 'flow' | 'typescript', ): Array< - NodePath< - t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression - > + | NodePath + | NodePath + | NodePath > { const items: Array< - NodePath< - t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression - > + | NodePath + | NodePath + | NodePath > = []; try { const ast = parseInput(source, language); @@ -155,22 +155,33 @@ function isHookName(s: string): boolean { return /^use[A-Z0-9]/.test(s); } -function getReactFunctionType( - id: NodePath, -): ReactFunctionType { - if (id && id.node && id.isIdentifier()) { - if (isHookName(id.node.name)) { +function getReactFunctionType(id: t.Identifier | null): ReactFunctionType { + if (id != null) { + if (isHookName(id.name)) { return 'Hook'; } const isPascalCaseNameSpace = /^[A-Z].*/; - if (isPascalCaseNameSpace.test(id.node.name)) { + if (isPascalCaseNameSpace.test(id.name)) { return 'Component'; } } return 'Other'; } +function getFunctionIdentifier( + fn: + | NodePath + | NodePath + | NodePath, +): t.Identifier | null { + if (fn.isArrowFunctionExpression()) { + return null; + } + const id = fn.get('id'); + return Array.isArray(id) === false && id.isIdentifier() ? id.node : null; +} + function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { const results = new Map(); const error = new CompilerError(); @@ -188,27 +199,21 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { } else { language = 'typescript'; } + let count = 0; + const withIdentifier = (id: t.Identifier | null): t.Identifier => { + if (id != null && id.name != null) { + return id; + } else { + return t.identifier(`anonymous_${count++}`); + } + }; try { // Extract the first line to quickly check for custom test directives const pragma = source.substring(0, source.indexOf('\n')); const config = parseConfigPragma(pragma); for (const fn of parseFunctions(source, language)) { - if (!fn.isFunctionDeclaration()) { - error.pushErrorDetail( - new CompilerErrorDetail({ - reason: `Unexpected function type ${fn.node.type}`, - description: - 'Playground only supports parsing function declarations', - severity: ErrorSeverity.Todo, - loc: fn.node.loc ?? null, - suggestions: null, - }), - ); - continue; - } - - const id = fn.get('id'); + const id = withIdentifier(getFunctionIdentifier(fn)); for (const result of run( fn, { @@ -221,7 +226,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { null, null, )) { - const fnName = fn.node.id?.name ?? null; + const fnName = id.name; switch (result.kind) { case 'ast': { upsert({ @@ -230,7 +235,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { name: result.name, value: { type: 'FunctionDeclaration', - id: result.value.id, + id, async: result.value.async, generator: result.value.generator, body: result.value.body, From 13ddf1084b4304a60059e3b96fc3c039d23e9432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 16 Aug 2024 19:52:11 -0400 Subject: [PATCH 013/426] [DevTools] Find owners from the parent path that matches the Fiber or ReactComponentInfo (#30717) This enables finding Server Components on the owner path. Server Components aren't stateful so there's not actually one specific owner that it necessarily matches. So it can't be a global look up. E.g. the same Server Component can be rendered in two places or even nested inside each other. Therefore we need to find an appropriate instance using a heuristic. We can do that by traversing the parent path since the owner is likely also a parent. Not always but almost always. To simplify things we can also do the same for Fibers. That brings us one step closer to being able to get rid of the global fiberToFiberInstance map since we can just use the shadow tree to find this information. This does mean that we can't find owners that aren't parents which is usually ok. However, there is a test case that's interesting where you have a React ART tree inside a DOM tree. In that case the owners actually span multiple renderers and roots so the owner is not on the parent stack. Usually this is fine since you'd just care about the owners within React ART but ideally we'd support this. However, I think that really the fix to this is that the React ART tree itself should actually show up inside the DOM tree in DevTools and in the virtual shadow tree because that's conceptually where it belongs. That would then solve this particular issue. We'd just need some way to associate the root with a DOM parent when it gets mounted. --- .../src/__tests__/inspectedElement-test.js | 43 ++-- .../src/backend/fiber/renderer.js | 208 ++++++++++++------ 2 files changed, 159 insertions(+), 92 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index c77013aba3e71..843c6dff9c08f 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -2893,26 +2893,29 @@ describe('InspectedElement', () => { `); const inspectedElement = await inspectElementAtIndex(4); - expect(inspectedElement.owners).toMatchInlineSnapshot(` - [ - { - "compiledWithForget": false, - "displayName": "Child", - "hocDisplayNames": null, - "id": 8, - "key": null, - "type": 5, - }, - { - "compiledWithForget": false, - "displayName": "App", - "hocDisplayNames": null, - "id": 7, - "key": null, - "type": 5, - }, - ] - `); + // TODO: Ideally this should match the owners of the Group but those are + // part of a different parent tree. Ideally the Group would be parent of + // that parent tree though which would fix this issue. + // + // [ + // { + // "compiledWithForget": false, + // "displayName": "Child", + // "hocDisplayNames": null, + // "id": 8, + // "key": null, + // "type": 5, + // }, + // { + // "compiledWithForget": false, + // "displayName": "App", + // "hocDisplayNames": null, + // "id": 7, + // "key": null, + // "type": 5, + // }, + // ] + expect(inspectedElement.owners).toMatchInlineSnapshot(`[]`); }); describe('error boundary', () => { diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index a48b22f647548..62eacdf5dbe9a 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -2143,29 +2143,18 @@ export function attach( const {key} = fiber; const displayName = getDisplayNameForFiber(fiber); const elementType = getElementTypeForFiber(fiber); - const debugOwner = fiber._debugOwner; - - // Ideally we should call getFiberIDThrows() for _debugOwner, - // since owners are almost always higher in the tree (and so have already been processed), - // but in some (rare) instances reported in open source, a descendant mounts before an owner. - // Since this is a DEV only field it's probably okay to also just lazily generate and ID here if needed. - // See https://github.com/facebook/react/issues/21445 - let ownerID: number; - if (debugOwner != null) { - if (typeof debugOwner.tag === 'number') { - const ownerFiberInstance = getFiberInstanceUnsafe((debugOwner: any)); - if (ownerFiberInstance !== null) { - ownerID = ownerFiberInstance.id; - } else { - ownerID = 0; - } - } else { - // TODO: Track Server Component Owners. - ownerID = 0; - } - } else { - ownerID = 0; - } + + // Finding the owner instance might require traversing the whole parent path which + // doesn't have great big O notation. Ideally we'd lazily fetch the owner when we + // need it but we have some synchronous operations in the front end like Alt+Left + // which selects the owner immediately. Typically most owners are only a few parents + // away so maybe it's not so bad. + const debugOwner = getUnfilteredOwner(fiber); + const ownerInstance = findNearestOwnerInstance( + parentInstance, + debugOwner, + ); + const ownerID = ownerInstance === null ? 0 : ownerInstance.id; const parentID = parentInstance ? parentInstance.id : 0; const displayNameStringID = getStringID(displayName); @@ -2231,11 +2220,15 @@ export function attach( displayName = env + '(' + displayName + ')'; } const elementType = ElementTypeVirtual; - // TODO: Support Virtual Owners. To do this we need to find a matching - // virtual instance which is not a super cheap parent traversal and so - // we should ideally only do that lazily. We should maybe change the - // frontend to get it lazily. - const ownerID: number = 0; + + // Finding the owner instance might require traversing the whole parent path which + // doesn't have great big O notation. Ideally we'd lazily fetch the owner when we + // need it but we have some synchronous operations in the front end like Alt+Left + // which selects the owner immediately. Typically most owners are only a few parents + // away so maybe it's not so bad. + const debugOwner = getUnfilteredOwner(componentInfo); + const ownerInstance = findNearestOwnerInstance(parentInstance, debugOwner); + const ownerID = ownerInstance === null ? 0 : ownerInstance.id; const parentID = parentInstance ? parentInstance.id : 0; const displayNameStringID = getStringID(displayName); @@ -3354,11 +3347,19 @@ export function attach( } function getUpdatersList(root: any): Array | null { - return root.memoizedUpdaters != null - ? Array.from(root.memoizedUpdaters) - .filter(fiber => getFiberIDUnsafe(fiber) !== null) - .map(fiberToSerializedElement) - : null; + const updaters = root.memoizedUpdaters; + if (updaters == null) { + return null; + } + const result = []; + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const updater of updaters) { + const inst = getFiberInstanceUnsafe(updater); + if (inst !== null) { + result.push(instanceToSerializedElement(inst)); + } + } + return result; } function handleCommitFiberUnmount(fiber: any) { @@ -3923,13 +3924,26 @@ export function attach( } } - function fiberToSerializedElement(fiber: Fiber): SerializedElement { - return { - displayName: getDisplayNameForFiber(fiber) || 'Anonymous', - id: getFiberIDThrows(fiber), - key: fiber.key, - type: getElementTypeForFiber(fiber), - }; + function instanceToSerializedElement( + instance: DevToolsInstance, + ): SerializedElement { + if (instance.kind === FIBER_INSTANCE) { + const fiber = instance.data; + return { + displayName: getDisplayNameForFiber(fiber) || 'Anonymous', + id: instance.id, + key: fiber.key, + type: getElementTypeForFiber(fiber), + }; + } else { + const componentInfo = instance.data; + return { + displayName: componentInfo.name || 'Anonymous', + id: instance.id, + key: componentInfo.key == null ? null : componentInfo.key, + type: ElementTypeVirtual, + }; + } } function getOwnersList(id: number): Array | null { @@ -3938,33 +3952,97 @@ export function attach( console.warn(`Could not find DevToolsInstance with id "${id}"`); return null; } - if (devtoolsInstance.kind !== FIBER_INSTANCE) { - // TODO: Handle VirtualInstance. - return null; + const self = instanceToSerializedElement(devtoolsInstance); + const owners = getOwnersListFromInstance(devtoolsInstance); + // This is particular API is prefixed with the current instance too for some reason. + if (owners === null) { + return [self]; } - const fiber = - findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance); - if (fiber == null) { + owners.unshift(self); + owners.reverse(); + return owners; + } + + function getOwnersListFromInstance( + instance: DevToolsInstance, + ): Array | null { + let owner = getUnfilteredOwner(instance.data); + if (owner === null) { return null; } + const owners: Array = []; + let parentInstance: null | DevToolsInstance = instance.parent; + while (parentInstance !== null && owner !== null) { + const ownerInstance = findNearestOwnerInstance(parentInstance, owner); + if (ownerInstance !== null) { + owners.push(instanceToSerializedElement(ownerInstance)); + // Get the next owner and keep searching from the previous match. + owner = getUnfilteredOwner(owner); + parentInstance = ownerInstance.parent; + } else { + break; + } + } + return owners; + } - const owners: Array = [fiberToSerializedElement(fiber)]; - - let owner = fiber._debugOwner; - while (owner != null) { + function getUnfilteredOwner( + owner: ReactComponentInfo | Fiber | null | void, + ): ReactComponentInfo | Fiber | null { + if (owner == null) { + return null; + } + if (typeof owner.tag === 'number') { + const ownerFiber: Fiber = (owner: any); // Refined + owner = ownerFiber._debugOwner; + } else { + const ownerInfo: ReactComponentInfo = (owner: any); // Refined + owner = ownerInfo.owner; + } + while (owner) { if (typeof owner.tag === 'number') { const ownerFiber: Fiber = (owner: any); // Refined if (!shouldFilterFiber(ownerFiber)) { - owners.unshift(fiberToSerializedElement(ownerFiber)); + return ownerFiber; } owner = ownerFiber._debugOwner; } else { - // TODO: Track Server Component Owners. - break; + const ownerInfo: ReactComponentInfo = (owner: any); // Refined + if (!shouldFilterVirtual(ownerInfo)) { + return ownerInfo; + } + owner = ownerInfo.owner; } } + return null; + } - return owners; + function findNearestOwnerInstance( + parentInstance: null | DevToolsInstance, + owner: void | null | ReactComponentInfo | Fiber, + ): null | DevToolsInstance { + if (owner == null) { + return null; + } + // Search the parent path for any instance that matches this kind of owner. + while (parentInstance !== null) { + if ( + parentInstance.data === owner || + // Typically both owner and instance.data would refer to the current version of a Fiber + // but it is possible for memoization to ignore the owner on the JSX. Then the new Fiber + // isn't propagated down as the new owner. In that case we might match the alternate + // instead. This is a bit hacky but the fastest check since type casting owner to a Fiber + // needs a duck type check anyway. + parentInstance.data === (owner: any).alternate + ) { + return parentInstance; + } + parentInstance = parentInstance.parent; + } + // It is technically possible to create an element and render it in a different parent + // but this is a weird edge case and it is worth not having to scan the tree or keep + // a register for every fiber/component info. + return null; } // Fast path props lookup for React Native style editor. @@ -4047,7 +4125,6 @@ export function attach( } const { - _debugOwner: debugOwner, stateNode, key, memoizedProps, @@ -4174,21 +4251,8 @@ export function attach( context = {value: context}; } - let owners: null | Array = null; - let owner = debugOwner; - while (owner != null) { - if (typeof owner.tag === 'number') { - const ownerFiber: Fiber = (owner: any); // Refined - if (owners === null) { - owners = []; - } - owners.push(fiberToSerializedElement(ownerFiber)); - owner = ownerFiber._debugOwner; - } else { - // TODO: Track Server Component Owners. - break; - } - } + const owners: null | Array = + getOwnersListFromInstance(fiberInstance); const isTimedOutSuspense = tag === SuspenseComponent && memoizedState !== null; @@ -4352,8 +4416,8 @@ export function attach( displayName = env + '(' + displayName + ')'; } - // TODO: Support Virtual Owners. - const owners: null | Array = null; + const owners: null | Array = + getOwnersListFromInstance(virtualInstance); let rootType = null; let targetErrorBoundaryID = null; From 177b2419b2d8a3d14c3f3304bb7e300985d6f377 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Fri, 16 Aug 2024 16:45:03 -0700 Subject: [PATCH 014/426] [compiler] Validate environment config while parsing plugin opts Addresses a todo from a while back. We now validate environment options when parsing the plugin options, which means we can stop re-parsing/validating in later phases. ghstack-source-id: b19806e843e1254716705b33dcf86afb7223f6c7 Pull Request resolved: https://github.com/facebook/react/pull/30726 --- .../src/Entrypoint/Options.ts | 26 +++++++++++++++---- .../src/Entrypoint/Program.ts | 17 +----------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index e97ececc2a137..e966497256511 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -7,8 +7,12 @@ import * as t from '@babel/types'; import {z} from 'zod'; -import {CompilerErrorDetailOptions} from '../CompilerError'; -import {ExternalFunction, PartialEnvironmentConfig} from '../HIR/Environment'; +import {CompilerError, CompilerErrorDetailOptions} from '../CompilerError'; +import { + EnvironmentConfig, + ExternalFunction, + parseEnvironmentConfig, +} from '../HIR/Environment'; import {hasOwnProperty} from '../Utils/utils'; const PanicThresholdOptionsSchema = z.enum([ @@ -32,7 +36,7 @@ const PanicThresholdOptionsSchema = z.enum([ export type PanicThresholdOptions = z.infer; export type PluginOptions = { - environment: PartialEnvironmentConfig | null; + environment: EnvironmentConfig; logger: Logger | null; @@ -194,7 +198,7 @@ export type Logger = { export const defaultOptions: PluginOptions = { compilationMode: 'infer', panicThreshold: 'none', - environment: {}, + environment: parseEnvironmentConfig({}).unwrap(), logger: null, gating: null, noEmit: false, @@ -218,7 +222,19 @@ export function parsePluginOptions(obj: unknown): PluginOptions { // normalize string configs to be case insensitive value = value.toLowerCase(); } - if (isCompilerFlag(key)) { + if (key === 'environment') { + const environmentResult = parseEnvironmentConfig(value); + if (environmentResult.isErr()) { + CompilerError.throwInvalidConfig({ + reason: + 'Error in validating environment config. This is an advanced setting and not meant to be used directly', + description: environmentResult.unwrapErr().toString(), + suggestions: null, + loc: null, + }); + } + parsedOptions[key] = environmentResult.unwrap(); + } else if (isCompilerFlag(key)) { parsedOptions[key] = value; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 99ec1e04a65e4..979e9f88d1b57 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -16,7 +16,6 @@ import { EnvironmentConfig, ExternalFunction, ReactFunctionType, - parseEnvironmentConfig, tryParseExternalFunction, } from '../HIR/Environment'; import {CodegenFunction} from '../ReactiveScopes'; @@ -292,21 +291,7 @@ export function compileProgram( return; } - /* - * TODO(lauren): Remove pass.opts.environment nullcheck once PluginOptions - * is validated - */ - const environmentResult = parseEnvironmentConfig(pass.opts.environment ?? {}); - if (environmentResult.isErr()) { - CompilerError.throwInvalidConfig({ - reason: - 'Error in validating environment config. This is an advanced setting and not meant to be used directly', - description: environmentResult.unwrapErr().toString(), - suggestions: null, - loc: null, - }); - } - const environment = environmentResult.unwrap(); + const environment = pass.opts.environment; const restrictedImportsErr = validateRestrictedImports(program, environment); if (restrictedImportsErr) { handleError(restrictedImportsErr, pass, null); From 7954db9398b9afa962167577a6c6940be3856c39 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 16 Aug 2024 18:29:18 -0700 Subject: [PATCH 015/426] [Fizz] handle throwing after abort during render (#30730) It is possible to throw after aborting during a render and we were not properly tracking this. We use an AbortSigil to mark whether a rendering task needs to abort but the throw interrupts that and we end up handling an error on the error pathway instead. This change reworks the abort-while-rendering support to be robust to throws after calling abort --- .../src/__tests__/ReactDOMFizzServer-test.js | 42 +++++++++++++++++++ packages/react-server/src/ReactFizzServer.js | 22 +++++----- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index e9abb25eb1768..5d70a0c71ea4d 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -8377,6 +8377,48 @@ describe('ReactDOMFizzServer', () => { ); }); + it('can support throwing after aborting during a render', async () => { + function App() { + return ( +
+ loading...

}> + +
+
+ ); + } + + function ComponentThatAborts() { + abortRef.current('boom'); + throw new Error('bam'); + } + + const abortRef = {current: null}; + let finished = false; + const errors = []; + await act(() => { + const {pipe, abort} = renderToPipeableStream(, { + onError(err) { + errors.push(err); + }, + }); + abortRef.current = abort; + writable.on('finish', () => { + finished = true; + }); + pipe(writable); + }); + + expect(errors).toEqual(['boom']); + + expect(finished).toBe(true); + expect(getVisibleChildren(container)).toEqual( +
+

loading...

+
, + ); + }); + it('should warn for using generators as children props', async () => { function* getChildren() { yield

Hello

; diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index a6c77f8bafb7f..986e8673a5a2a 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -652,8 +652,6 @@ export function resumeRequest( return request; } -const AbortSigil = {}; - let currentRequest: null | Request = null; export function resolveRequest(): null | Request { @@ -1173,7 +1171,7 @@ function renderSuspenseBoundary( ); boundarySegment.status = COMPLETED; } catch (thrownValue: mixed) { - if (thrownValue === AbortSigil) { + if (request.status === ABORTING) { boundarySegment.status = ABORTED; } else { boundarySegment.status = ERRORED; @@ -1246,7 +1244,7 @@ function renderSuspenseBoundary( } catch (thrownValue: mixed) { newBoundary.status = CLIENT_RENDERED; let error: mixed; - if (thrownValue === AbortSigil) { + if (request.status === ABORTING) { contentRootSegment.status = ABORTED; error = request.fatalError; } else { @@ -1601,7 +1599,8 @@ function finishClassComponent( nextChildren = instance.render(); } if (request.status === ABORTING) { - throw AbortSigil; + // eslint-disable-next-line no-throw-literal + throw null; } if (__DEV__) { @@ -1757,7 +1756,8 @@ function renderFunctionComponent( legacyContext, ); if (request.status === ABORTING) { - throw AbortSigil; + // eslint-disable-next-line no-throw-literal + throw null; } const hasId = checkDidRenderIdHook(); @@ -2076,7 +2076,8 @@ function renderLazyComponent( Component = init(payload); } if (request.status === ABORTING) { - throw AbortSigil; + // eslint-disable-next-line no-throw-literal + throw null; } const resolvedProps = resolveDefaultPropsOnNonClassComponent( Component, @@ -2655,7 +2656,8 @@ function retryNode(request: Request, task: Task): void { resolvedNode = init(payload); } if (request.status === ABORTING) { - throw AbortSigil; + // eslint-disable-next-line no-throw-literal + throw null; } // Now we render the resolved node renderNodeDestructive(request, task, resolvedNode, childIndex); @@ -4127,7 +4129,7 @@ function retryRenderTask( // (unstable) API for suspending. This implementation detail can change // later, once we deprecate the old API in favor of `use`. getSuspendedThenable() - : thrownValue === AbortSigil + : request.status === ABORTING ? request.fatalError : thrownValue; @@ -4250,7 +4252,7 @@ function retryReplayTask(request: Request, task: ReplayTask): void { erroredReplay( request, task.blockedBoundary, - x === AbortSigil ? request.fatalError : x, + request.status === ABORTING ? request.fatalError : x, errorInfo, task.replay.nodes, task.replay.slots, From 6ebfd5b0829c3e7a977ef4d9a0bd96436c681251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 18 Aug 2024 12:31:45 -0400 Subject: [PATCH 016/426] [Flight] Source Map Server Actions to their Server Location (#30741) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This uses a similar technique to what we use to generate fake stack frames for server components. This generates an eval:ed wrapper function around the Server Reference proxy we create on the client. This wrapper function gets the original `name` of the action on the server and I also add a source map if `findSourceMapURL` is defined that points back to the source of the server function. For `"use server"` on the server, there's no new API. It just uses the callsite of `registerServerReference()` on the Server. We can infer the function name from the actual function on the server and we already have the `findSourceMapURL` on the client receiving it. For `"use server"` imported from the client, there's two new options added to `createServerReference()` (in addition to the optional [`encodeFormAction`](#27563)). These are only used in DEV mode. The [`findSourceMapURL`](#29708) option is the same one added in #29708. We need to pass this these references aren't created in the context of any specific request but globally. The other weird thing about this case is that this is actually a case where the compiled environment is the client so any source maps are the same as for the client layer, so the environment name here is just `"Client"`. ```diff createServerReference( id: string, callServer: CallServerCallback, encodeFormAction?: EncodeFormActionCallback, + findSourceMapURL?: FindSourceMapURLCallback, // DEV-only + functionName?: string, // DEV-only ) ``` The key is that we use the location of the `registerServerReference()`/`createServerReference()` call as the location of the function. A compiler can either emit those at the same locations as the original functions or use source maps to have those segments refer to the original location of the function (or in the case of a re-export the original location of the re-export is also a fine approximate). The compiled output must call these directly without a wrapper function because the wrapper adds a stack frame. I decided against complicated and fragile dev-only options to skip n number of frames that would just end up in prod code. The implementation just skips one frame - our own. Otherwise it'll just point all source mapping to the wrapper. We don't have a `"use server"` imported from the client implementation in the reference implementation/fixture so it's a bit tricky to test that. In the case of CJS on the server, we just use a runtime instead of compiler so it's tricky to source map those appropriately. We can implement it for ESM on the server which is the main thing we're testing in the fixture. It's easier in a real implementation where all the compilation is just one pass. It's a little tricky since we have to parse and append to other source maps but I'd like to do that as a follow up. Or maybe that's just an exercise for the reader. You can right click an action and click "Go to Definition". Screenshot 2024-08-17 at 6 04 27 PM For now they simply don't point to the right place but you can still jump to the right file in the fixture: Screenshot 2024-08-17 at 5 58 40 PM In Firefox/Safari given that the location doesn't exist in the source map yet, the browser refuses to open the file. Where as Chrome does nearest (last) line. --- .../react-client/src/ReactFlightClient.js | 39 ++- .../src/ReactFlightReplyClient.js | 248 +++++++++++++++++- .../src/ReactFlightESMReferences.js | 33 ++- .../ReactFlightServerConfigESMBundler.js | 7 + .../src/ReactFlightTurbopackReferences.js | 36 ++- ...ReactFlightServerConfigTurbopackBundler.js | 7 + .../src/ReactFlightWebpackReferences.js | 36 ++- .../__tests__/ReactFlightDOMBrowser-test.js | 12 + .../ReactFlightServerConfigWebpackBundler.js | 7 + .../react-server/src/ReactFlightServer.js | 42 ++- .../ReactFlightServerConfigBundlerCustom.js | 1 + .../forks/ReactFlightServerConfig.markup.js | 7 + 12 files changed, 418 insertions(+), 57 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 564f4e859871f..c386d503bfe6b 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -13,6 +13,7 @@ import type { ReactComponentInfo, ReactAsyncInfo, ReactStackTrace, + ReactCallSite, } from 'shared/ReactTypes'; import type {LazyComponent} from 'react/src/ReactLazy'; @@ -59,7 +60,7 @@ import { bindToConsole, } from './ReactFlightClientConfig'; -import {registerServerReference} from './ReactFlightReplyClient'; +import {createBoundServerReference} from './ReactFlightReplyClient'; import {readTemporaryReference} from './ReactFlightTemporaryReferences'; @@ -1001,30 +1002,20 @@ function waitForReference( function createServerReferenceProxy, T>( response: Response, - metaData: {id: any, bound: null | Thenable>}, + metaData: { + id: any, + bound: null | Thenable>, + name?: string, // DEV-only + env?: string, // DEV-only + location?: ReactCallSite, // DEV-only + }, ): (...A) => Promise { - const callServer = response._callServer; - const proxy = function (): Promise { - // $FlowFixMe[method-unbinding] - const args = Array.prototype.slice.call(arguments); - const p = metaData.bound; - if (!p) { - return callServer(metaData.id, args); - } - if (p.status === INITIALIZED) { - const bound = p.value; - return callServer(metaData.id, bound.concat(args)); - } - // Since this is a fake Promise whose .then doesn't chain, we have to wrap it. - // TODO: Remove the wrapper once that's fixed. - return ((Promise.resolve(p): any): Promise>).then( - function (bound) { - return callServer(metaData.id, bound.concat(args)); - }, - ); - }; - registerServerReference(proxy, metaData, response._encodeFormAction); - return proxy; + return createBoundServerReference( + metaData, + response._callServer, + response._encodeFormAction, + __DEV__ ? response._debugFindSourceMapURL : undefined, + ); } function getOutlinedModel( diff --git a/packages/react-client/src/ReactFlightReplyClient.js b/packages/react-client/src/ReactFlightReplyClient.js index c4033a999d96d..233f51844e2a3 100644 --- a/packages/react-client/src/ReactFlightReplyClient.js +++ b/packages/react-client/src/ReactFlightReplyClient.js @@ -13,6 +13,7 @@ import type { FulfilledThenable, RejectedThenable, ReactCustomFormAction, + ReactCallSite, } from 'shared/ReactTypes'; import type {LazyComponent} from 'react/src/ReactLazy'; import type {TemporaryReferenceSet} from './ReactFlightTemporaryReferences'; @@ -1023,7 +1024,99 @@ function isSignatureEqual( } } -export function registerServerReference( +let fakeServerFunctionIdx = 0; + +function createFakeServerFunction, T>( + name: string, + filename: string, + sourceMap: null | string, + line: number, + col: number, + environmentName: string, + innerFunction: (...A) => Promise, +): (...A) => Promise { + // This creates a fake copy of a Server Module. It represents the Server Action on the server. + // We use an eval so we can source map it to the original location. + + const comment = + '/* This module is a proxy to a Server Action. Turn on Source Maps to see the server source. */'; + + if (!name) { + // An eval:ed function with no name gets the name "eval". We give it something more descriptive. + name = ''; + } + const encodedName = JSON.stringify(name); + // We generate code where both the beginning of the function and its parenthesis is at the line + // and column of the server executed code. We use a method form since that lets us name it + // anything we want and because the beginning of the function and its parenthesis is the same + // column. Because Chrome inspects the location of the parenthesis and Firefox inspects the + // location of the beginning of the function. By not using a function expression we avoid the + // ambiguity. + let code; + if (line <= 1) { + const minSize = encodedName.length + 7; + code = + 's=>({' + + encodedName + + ' '.repeat(col < minSize ? 0 : col - minSize) + + ':' + + '(...args) => s(...args)' + + '})\n' + + comment; + } else { + code = + comment + + '\n'.repeat(line - 2) + + 'server=>({' + + encodedName + + ':\n' + + ' '.repeat(col < 1 ? 0 : col - 1) + + // The function body can get printed so we make it look nice. + // This "calls the server with the arguments". + '(...args) => server(...args)' + + '})'; + } + + if (filename.startsWith('/')) { + // If the filename starts with `/` we assume that it is a file system file + // rather than relative to the current host. Since on the server fully qualified + // stack traces use the file path. + // TODO: What does this look like on Windows? + filename = 'file://' + filename; + } + + if (sourceMap) { + // We use the prefix rsc://React/ to separate these from other files listed in + // the Chrome DevTools. We need a "host name" and not just a protocol because + // otherwise the group name becomes the root folder. Ideally we don't want to + // show these at all but there's two reasons to assign a fake URL. + // 1) A printed stack trace string needs a unique URL to be able to source map it. + // 2) If source maps are disabled or fails, you should at least be able to tell + // which file it was. + code += + '\n//# sourceURL=rsc://React/' + + encodeURIComponent(environmentName) + + '/' + + filename + + '?s' + // We add an extra s here to distinguish from the fake stack frames + fakeServerFunctionIdx++; + code += '\n//# sourceMappingURL=' + sourceMap; + } else if (filename) { + code += '\n//# sourceURL=' + filename; + } + + try { + // Eval a factory and then call it to create a closure over the inner function. + // eslint-disable-next-line no-eval + return (0, eval)(code)(innerFunction)[name]; + } catch (x) { + // If eval fails, such as if in an environment that doesn't support it, + // we fallback to just returning the inner function. + return innerFunction; + } +} + +function registerServerReference( proxy: any, reference: {id: ServerReferenceId, bound: null | Thenable>}, encodeFormAction: void | EncodeFormActionCallback, @@ -1098,16 +1191,163 @@ function bind(this: Function): Function { return newFn; } +export type FindSourceMapURLCallback = ( + fileName: string, + environmentName: string, +) => null | string; + +export function createBoundServerReference, T>( + metaData: { + id: ServerReferenceId, + bound: null | Thenable>, + name?: string, // DEV-only + env?: string, // DEV-only + location?: ReactCallSite, // DEV-only + }, + callServer: CallServerCallback, + encodeFormAction?: EncodeFormActionCallback, + findSourceMapURL?: FindSourceMapURLCallback, // DEV-only +): (...A) => Promise { + const id = metaData.id; + const bound = metaData.bound; + let action = function (): Promise { + // $FlowFixMe[method-unbinding] + const args = Array.prototype.slice.call(arguments); + const p = bound; + if (!p) { + return callServer(id, args); + } + if (p.status === 'fulfilled') { + const boundArgs = p.value; + return callServer(id, boundArgs.concat(args)); + } + // Since this is a fake Promise whose .then doesn't chain, we have to wrap it. + // TODO: Remove the wrapper once that's fixed. + return ((Promise.resolve(p): any): Promise>).then( + function (boundArgs) { + return callServer(id, boundArgs.concat(args)); + }, + ); + }; + if (__DEV__) { + const location = metaData.location; + if (location) { + const functionName = metaData.name || ''; + const [, filename, line, col] = location; + const env = metaData.env || 'Server'; + const sourceMap = + findSourceMapURL == null ? null : findSourceMapURL(filename, env); + action = createFakeServerFunction( + functionName, + filename, + sourceMap, + line, + col, + env, + action, + ); + } + } + registerServerReference(action, {id, bound}, encodeFormAction); + return action; +} + +// This matches either of these V8 formats. +// at name (filename:0:0) +// at filename:0:0 +// at async filename:0:0 +const v8FrameRegExp = + /^ {3} at (?:(.+) \((.+):(\d+):(\d+)\)|(?:async )?(.+):(\d+):(\d+))$/; +// This matches either of these JSC/SpiderMonkey formats. +// name@filename:0:0 +// filename:0:0 +const jscSpiderMonkeyFrameRegExp = /(?:(.*)@)?(.*):(\d+):(\d+)/; + +function parseStackLocation(error: Error): null | ReactCallSite { + // This parsing is special in that we know that the calling function will always + // be a module that initializes the server action. We also need this part to work + // cross-browser so not worth a Config. It's DEV only so not super code size + // sensitive but also a non-essential feature. + let stack = error.stack; + if (stack.startsWith('Error: react-stack-top-frame\n')) { + // V8's default formatting prefixes with the error message which we + // don't want/need. + stack = stack.slice(29); + } + const endOfFirst = stack.indexOf('\n'); + let secondFrame; + if (endOfFirst !== -1) { + // Skip the first frame. + const endOfSecond = stack.indexOf('\n', endOfFirst + 1); + if (endOfSecond === -1) { + secondFrame = stack.slice(endOfFirst + 1); + } else { + secondFrame = stack.slice(endOfFirst + 1, endOfSecond); + } + } else { + secondFrame = stack; + } + + let parsed = v8FrameRegExp.exec(secondFrame); + if (!parsed) { + parsed = jscSpiderMonkeyFrameRegExp.exec(secondFrame); + if (!parsed) { + return null; + } + } + + let name = parsed[1] || ''; + if (name === '') { + name = ''; + } + let filename = parsed[2] || parsed[5] || ''; + if (filename === '') { + filename = ''; + } + const line = +(parsed[3] || parsed[6]); + const col = +(parsed[4] || parsed[7]); + + return [name, filename, line, col]; +} + export function createServerReference, T>( id: ServerReferenceId, callServer: CallServerCallback, encodeFormAction?: EncodeFormActionCallback, + findSourceMapURL?: FindSourceMapURLCallback, // DEV-only + functionName?: string, ): (...A) => Promise { - const proxy = function (): Promise { + let action = function (): Promise { // $FlowFixMe[method-unbinding] const args = Array.prototype.slice.call(arguments); return callServer(id, args); }; - registerServerReference(proxy, {id, bound: null}, encodeFormAction); - return proxy; + if (__DEV__) { + // Let's see if we can find a source map for the file which contained the + // server action. We extract it from the runtime so that it's resilient to + // multiple passes of compilation as long as we can find the final source map. + const location = parseStackLocation(new Error('react-stack-top-frame')); + if (location !== null) { + const [, filename, line, col] = location; + // While the environment that the Server Reference points to can be + // in any environment, what matters here is where the compiled source + // is from and that's in the currently executing environment. We hard + // code that as the value "Client" in case the findSourceMapURL helper + // needs it. + const env = 'Client'; + const sourceMap = + findSourceMapURL == null ? null : findSourceMapURL(filename, env); + action = createFakeServerFunction( + functionName || '', + filename, + sourceMap, + line, + col, + env, + action, + ); + } + } + registerServerReference(action, {id, bound: null}, encodeFormAction); + return action; } diff --git a/packages/react-server-dom-esm/src/ReactFlightESMReferences.js b/packages/react-server-dom-esm/src/ReactFlightESMReferences.js index cd3dd349157a5..86a25c7c8608a 100644 --- a/packages/react-server-dom-esm/src/ReactFlightESMReferences.js +++ b/packages/react-server-dom-esm/src/ReactFlightESMReferences.js @@ -13,6 +13,7 @@ export type ServerReference = T & { $$typeof: symbol, $$id: string, $$bound: null | Array, + $$location?: Error, }; // eslint-disable-next-line no-unused-vars @@ -68,10 +69,30 @@ export function registerServerReference( id: string, exportName: string, ): ServerReference { - return Object.defineProperties((reference: any), { - $$typeof: {value: SERVER_REFERENCE_TAG}, - $$id: {value: id + '#' + exportName, configurable: true}, - $$bound: {value: null, configurable: true}, - bind: {value: bind, configurable: true}, - }); + const $$typeof = {value: SERVER_REFERENCE_TAG}; + const $$id = { + value: id + '#' + exportName, + configurable: true, + }; + const $$bound = {value: null, configurable: true}; + return Object.defineProperties( + (reference: any), + __DEV__ + ? { + $$typeof, + $$id, + $$bound, + $$location: { + value: Error('react-stack-top-frame'), + configurable: true, + }, + bind: {value: bind, configurable: true}, + } + : { + $$typeof, + $$id, + $$bound, + bind: {value: bind, configurable: true}, + }, + ); } diff --git a/packages/react-server-dom-esm/src/server/ReactFlightServerConfigESMBundler.js b/packages/react-server-dom-esm/src/server/ReactFlightServerConfigESMBundler.js index cba5223bcf7af..5e789518b40cb 100644 --- a/packages/react-server-dom-esm/src/server/ReactFlightServerConfigESMBundler.js +++ b/packages/react-server-dom-esm/src/server/ReactFlightServerConfigESMBundler.js @@ -70,3 +70,10 @@ export function getServerReferenceBoundArguments( ): null | Array { return serverReference.$$bound; } + +export function getServerReferenceLocation( + config: ClientManifest, + serverReference: ServerReference, +): void | Error { + return serverReference.$$location; +} diff --git a/packages/react-server-dom-turbopack/src/ReactFlightTurbopackReferences.js b/packages/react-server-dom-turbopack/src/ReactFlightTurbopackReferences.js index ecf6a35dfa6ef..613a7e7dc862c 100644 --- a/packages/react-server-dom-turbopack/src/ReactFlightTurbopackReferences.js +++ b/packages/react-server-dom-turbopack/src/ReactFlightTurbopackReferences.js @@ -13,6 +13,7 @@ export type ServerReference = T & { $$typeof: symbol, $$id: string, $$bound: null | Array, + $$location?: Error, }; // eslint-disable-next-line no-unused-vars @@ -81,15 +82,32 @@ export function registerServerReference( id: string, exportName: null | string, ): ServerReference { - return Object.defineProperties((reference: any), { - $$typeof: {value: SERVER_REFERENCE_TAG}, - $$id: { - value: exportName === null ? id : id + '#' + exportName, - configurable: true, - }, - $$bound: {value: null, configurable: true}, - bind: {value: bind, configurable: true}, - }); + const $$typeof = {value: SERVER_REFERENCE_TAG}; + const $$id = { + value: exportName === null ? id : id + '#' + exportName, + configurable: true, + }; + const $$bound = {value: null, configurable: true}; + return Object.defineProperties( + (reference: any), + __DEV__ + ? { + $$typeof, + $$id, + $$bound, + $$location: { + value: Error('react-stack-top-frame'), + configurable: true, + }, + bind: {value: bind, configurable: true}, + } + : { + $$typeof, + $$id, + $$bound, + bind: {value: bind, configurable: true}, + }, + ); } const PROMISE_PROTOTYPE = Promise.prototype; diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js b/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js index 2ebc5d3f10421..d8224aff341dc 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js @@ -91,3 +91,10 @@ export function getServerReferenceBoundArguments( ): null | Array { return serverReference.$$bound; } + +export function getServerReferenceLocation( + config: ClientManifest, + serverReference: ServerReference, +): void | Error { + return serverReference.$$location; +} diff --git a/packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js b/packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js index 6d14f412063c1..025a7368213f8 100644 --- a/packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js +++ b/packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js @@ -13,6 +13,7 @@ export type ServerReference = T & { $$typeof: symbol, $$id: string, $$bound: null | Array, + $$location?: Error, }; // eslint-disable-next-line no-unused-vars @@ -89,15 +90,32 @@ export function registerServerReference( id: string, exportName: null | string, ): ServerReference { - return Object.defineProperties((reference: any), { - $$typeof: {value: SERVER_REFERENCE_TAG}, - $$id: { - value: exportName === null ? id : id + '#' + exportName, - configurable: true, - }, - $$bound: {value: null, configurable: true}, - bind: {value: bind, configurable: true}, - }); + const $$typeof = {value: SERVER_REFERENCE_TAG}; + const $$id = { + value: exportName === null ? id : id + '#' + exportName, + configurable: true, + }; + const $$bound = {value: null, configurable: true}; + return Object.defineProperties( + (reference: any), + __DEV__ + ? { + $$typeof, + $$id, + $$bound, + $$location: { + value: Error('react-stack-top-frame'), + configurable: true, + }, + bind: {value: bind, configurable: true}, + } + : { + $$typeof, + $$id, + $$bound, + bind: {value: bind, configurable: true}, + }, + ); } const PROMISE_PROTOTYPE = Promise.prototype; diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index 7bbfea1484bed..969f9e125e8c5 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -1393,9 +1393,21 @@ describe('ReactFlightDOMBrowser', () => { const body = await ReactServerDOMClient.encodeReply(args); return callServer(ref, body); }, + undefined, + undefined, + 'upper', ), }; + expect(ServerModuleBImportedOnClient.upper.name).toBe( + __DEV__ ? 'upper' : 'action', + ); + if (__DEV__) { + expect(ServerModuleBImportedOnClient.upper.toString()).toBe( + '(...args) => server(...args)', + ); + } + function Client({action}) { // Client side pass a Server Reference into an action. actionProxy = text => action(ServerModuleBImportedOnClient.upper, text); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js b/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js index a0872b61fa475..d29516ff946ea 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js @@ -91,3 +91,10 @@ export function getServerReferenceBoundArguments( ): null | Array { return serverReference.$$bound; } + +export function getServerReferenceLocation( + config: ClientManifest, + serverReference: ServerReference, +): void | Error { + return serverReference.$$location; +} diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index db0ee7b3cebad..bfb12c31c7ffc 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -64,6 +64,7 @@ import type { ReactComponentInfo, ReactAsyncInfo, ReactStackTrace, + ReactCallSite, } from 'shared/ReactTypes'; import type {ReactElement} from 'shared/ReactElementType'; import type {LazyComponent} from 'react/src/ReactLazy'; @@ -72,6 +73,7 @@ import { resolveClientReferenceMetadata, getServerReferenceId, getServerReferenceBoundArguments, + getServerReferenceLocation, getClientReferenceKey, isClientReference, isServerReference, @@ -1955,17 +1957,47 @@ function serializeServerReference( return serializeServerReferenceID(existingId); } - const bound: null | Array = getServerReferenceBoundArguments( + const boundArgs: null | Array = getServerReferenceBoundArguments( request.bundlerConfig, serverReference, ); + const bound = boundArgs === null ? null : Promise.resolve(boundArgs); + const id = getServerReferenceId(request.bundlerConfig, serverReference); + + let location: null | ReactCallSite = null; + if (__DEV__) { + const error = getServerReferenceLocation( + request.bundlerConfig, + serverReference, + ); + if (error) { + const frames = parseStackTrace(error, 1); + if (frames.length > 0) { + location = frames[0]; + } + } + } + const serverReferenceMetadata: { id: ServerReferenceId, bound: null | Promise>, - } = { - id: getServerReferenceId(request.bundlerConfig, serverReference), - bound: bound ? Promise.resolve(bound) : null, - }; + name?: string, // DEV-only + env?: string, // DEV-only + location?: ReactCallSite, // DEV-only + } = + __DEV__ && location !== null + ? { + id, + bound, + name: + typeof serverReference === 'function' ? serverReference.name : '', + env: (0, request.environmentName)(), + location, + } + : { + id, + bound, + }; const metadataId = outlineModel(request, serverReferenceMetadata); writtenServerReferences.set(serverReference, metadataId); return serializeServerReferenceID(metadataId); diff --git a/packages/react-server/src/ReactFlightServerConfigBundlerCustom.js b/packages/react-server/src/ReactFlightServerConfigBundlerCustom.js index 00578a4da2459..ac3e17c630174 100644 --- a/packages/react-server/src/ReactFlightServerConfigBundlerCustom.js +++ b/packages/react-server/src/ReactFlightServerConfigBundlerCustom.js @@ -23,3 +23,4 @@ export const resolveClientReferenceMetadata = export const getServerReferenceId = $$$config.getServerReferenceId; export const getServerReferenceBoundArguments = $$$config.getServerReferenceBoundArguments; +export const getServerReferenceLocation = $$$config.getServerReferenceLocation; diff --git a/packages/react-server/src/forks/ReactFlightServerConfig.markup.js b/packages/react-server/src/forks/ReactFlightServerConfig.markup.js index 12feb37ac5697..7c879de39f271 100644 --- a/packages/react-server/src/forks/ReactFlightServerConfig.markup.js +++ b/packages/react-server/src/forks/ReactFlightServerConfig.markup.js @@ -90,3 +90,10 @@ export function getServerReferenceBoundArguments( 'Use a fixed URL for any forms instead.', ); } + +export function getServerReferenceLocation( + config: ClientManifest, + serverReference: ServerReference, +): void { + return undefined; +} From d2413bf377e7f73661b0700aeb95d07fb2911efc Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Fri, 16 Aug 2024 17:05:29 -0700 Subject: [PATCH 017/426] [compiler] Validate against JSX in try statements Per comments on the new validation pass, this disallows creating JSX (expression/fragment) within a try statement. Developers sometimes use this pattern thinking that they can catch errors during the rendering of the element, without realizing that rendering is lazy. The validation allows us to teach developers about the error boundary pattern. ghstack-source-id: 0bc722aeaed426ddd40e075c008f0ff2576e0c33 Pull Request resolved: https://github.com/facebook/react/pull/30725 --- .../src/Entrypoint/Pipeline.ts | 5 ++ .../src/HIR/Environment.ts | 6 ++ .../Validation/ValidateNoJSXInTryStatement.ts | 52 +++++++++++++++++ ...in-catch-in-outer-try-with-catch.expect.md | 38 +++++++++++++ ...id-jsx-in-catch-in-outer-try-with-catch.js | 17 ++++++ ...or.invalid-jsx-in-try-with-catch.expect.md | 31 ++++++++++ .../error.invalid-jsx-in-try-with-catch.js | 10 ++++ ...-catch-in-outer-try-with-finally.expect.md | 56 +++++++++++++++++++ ...-jsx-in-catch-in-outer-try-with-finally.js | 17 ++++++ ...-invalid-jsx-in-try-with-finally.expect.md | 39 +++++++++++++ ...or.todo-invalid-jsx-in-try-with-finally.js | 10 ++++ 11 files changed, 281 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 590aba2fdc0c4..8307e8817b4f9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -105,6 +105,7 @@ import {outlineFunctions} from '../Optimization/OutlineFunctions'; import {propagatePhiTypes} from '../TypeInference/PropagatePhiTypes'; import {lowerContextAccess} from '../Optimization/LowerContextAccess'; import {validateNoSetStateInPassiveEffects} from '../Validation/ValidateNoSetStateInPassiveEffects'; +import {validateNoJSXInTryStatement} from '../Validation/ValidateNoJSXInTryStatement'; export type CompilerPipelineValue = | {kind: 'ast'; name: string; value: CodegenFunction} @@ -249,6 +250,10 @@ function* runWithEnvironment( validateNoSetStateInPassiveEffects(hir); } + if (env.config.validateNoJSXInTryStatements) { + validateNoJSXInTryStatement(hir); + } + inferReactivePlaces(hir); yield log({kind: 'hir', name: 'InferReactivePlaces', value: hir}); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index ca03b8a7b1e39..a5614ac244a14 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -237,6 +237,12 @@ const EnvironmentConfigSchema = z.object({ */ validateNoSetStateInPassiveEffects: z.boolean().default(false), + /** + * Validates against creating JSX within a try block and recommends using an error boundary + * instead. + */ + validateNoJSXInTryStatements: z.boolean().default(false), + /** * Validates that the dependencies of all effect hooks are memoized. This helps ensure * that Forget does not introduce infinite renders caused by a dependency changing, diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts new file mode 100644 index 0000000000000..b92a89d764301 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoJSXInTryStatement.ts @@ -0,0 +1,52 @@ +/** + * 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 {CompilerError, ErrorSeverity} from '..'; +import {BlockId, HIRFunction} from '../HIR'; +import {retainWhere} from '../Utils/utils'; + +/** + * Developers may not be aware of error boundaries and lazy evaluation of JSX, leading them + * to use patterns such as `let el; try { el = } catch { ... }` to attempt to + * catch rendering errors. Such code will fail to catch errors in rendering, but developers + * may not realize this right away. + * + * This validation pass validates against this pattern: specifically, it errors for JSX + * created within a try block. JSX is allowed within a catch statement, unless that catch + * is itself nested inside an outer try. + */ +export function validateNoJSXInTryStatement(fn: HIRFunction): void { + const activeTryBlocks: Array = []; + const errors = new CompilerError(); + for (const [, block] of fn.body.blocks) { + retainWhere(activeTryBlocks, id => id !== block.id); + + if (activeTryBlocks.length !== 0) { + for (const instr of block.instructions) { + const {value} = instr; + switch (value.kind) { + case 'JsxExpression': + case 'JsxFragment': { + errors.push({ + severity: ErrorSeverity.InvalidReact, + reason: `Unexpected JSX element within a try statement. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary)`, + loc: value.loc, + }); + break; + } + } + } + } + + if (block.terminal.kind === 'try') { + activeTryBlocks.push(block.terminal.handler); + } + } + if (errors.hasErrors()) { + throw errors; + } +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.expect.md new file mode 100644 index 0000000000000..40cebff89a75e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.expect.md @@ -0,0 +1,38 @@ + +## Input + +```javascript +// @validateNoJSXInTryStatements +import {identity} from 'shared-runtime'; + +function Component(props) { + let el; + try { + let value; + try { + value = identity(props.foo); + } catch { + el =
; + } + } catch { + return null; + } + return el; +} + +``` + + +## Error + +``` + 9 | value = identity(props.foo); + 10 | } catch { +> 11 | el =
; + | ^^^^^^^^^^^^^^^^^^^^^ InvalidReact: Unexpected JSX element within a try statement. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) (11:11) + 12 | } + 13 | } catch { + 14 | return null; +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.js new file mode 100644 index 0000000000000..0935a1a63cd83 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-catch-in-outer-try-with-catch.js @@ -0,0 +1,17 @@ +// @validateNoJSXInTryStatements +import {identity} from 'shared-runtime'; + +function Component(props) { + let el; + try { + let value; + try { + value = identity(props.foo); + } catch { + el =
; + } + } catch { + return null; + } + return el; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.expect.md new file mode 100644 index 0000000000000..ee1f5335ef624 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.expect.md @@ -0,0 +1,31 @@ + +## Input + +```javascript +// @validateNoJSXInTryStatements +function Component(props) { + let el; + try { + el =
; + } catch { + return null; + } + return el; +} + +``` + + +## Error + +``` + 3 | let el; + 4 | try { +> 5 | el =
; + | ^^^^^^^ InvalidReact: Unexpected JSX element within a try statement. To catch errors in rendering a given component, wrap that component in an error boundary. (https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) (5:5) + 6 | } catch { + 7 | return null; + 8 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.js new file mode 100644 index 0000000000000..3e7747c875b3c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-jsx-in-try-with-catch.js @@ -0,0 +1,10 @@ +// @validateNoJSXInTryStatements +function Component(props) { + let el; + try { + el =
; + } catch { + return null; + } + return el; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md new file mode 100644 index 0000000000000..a7ea7b7739c6a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.expect.md @@ -0,0 +1,56 @@ + +## Input + +```javascript +// @validateNoJSXInTryStatements +import {identity} from 'shared-runtime'; + +function Component(props) { + let el; + try { + let value; + try { + value = identity(props.foo); + } catch { + el =
; + } + } finally { + console.log(el); + } + return el; +} + +``` + + +## Error + +``` + 4 | function Component(props) { + 5 | let el; +> 6 | try { + | ^^^^^ +> 7 | let value; + | ^^^^^^^^^^^^^^ +> 8 | try { + | ^^^^^^^^^^^^^^ +> 9 | value = identity(props.foo); + | ^^^^^^^^^^^^^^ +> 10 | } catch { + | ^^^^^^^^^^^^^^ +> 11 | el =
; + | ^^^^^^^^^^^^^^ +> 12 | } + | ^^^^^^^^^^^^^^ +> 13 | } finally { + | ^^^^^^^^^^^^^^ +> 14 | console.log(el); + | ^^^^^^^^^^^^^^ +> 15 | } + | ^^^^ Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (6:15) + 16 | return el; + 17 | } + 18 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js new file mode 100644 index 0000000000000..9db091a2fb7ed --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-catch-in-outer-try-with-finally.js @@ -0,0 +1,17 @@ +// @validateNoJSXInTryStatements +import {identity} from 'shared-runtime'; + +function Component(props) { + let el; + try { + let value; + try { + value = identity(props.foo); + } catch { + el =
; + } + } finally { + console.log(el); + } + return el; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md new file mode 100644 index 0000000000000..a6a85d4519bcb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.expect.md @@ -0,0 +1,39 @@ + +## Input + +```javascript +// @validateNoJSXInTryStatements +function Component(props) { + let el; + try { + el =
; + } finally { + console.log(el); + } + return el; +} + +``` + + +## Error + +``` + 2 | function Component(props) { + 3 | let el; +> 4 | try { + | ^^^^^ +> 5 | el =
; + | ^^^^^^^^^^^^^^^^^ +> 6 | } finally { + | ^^^^^^^^^^^^^^^^^ +> 7 | console.log(el); + | ^^^^^^^^^^^^^^^^^ +> 8 | } + | ^^^^ Todo: (BuildHIR::lowerStatement) Handle TryStatement without a catch clause (4:8) + 9 | return el; + 10 | } + 11 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js new file mode 100644 index 0000000000000..f0a17391c0eef --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-invalid-jsx-in-try-with-finally.js @@ -0,0 +1,10 @@ +// @validateNoJSXInTryStatements +function Component(props) { + let el; + try { + el =
; + } finally { + console.log(el); + } + return el; +} From 9d082b550086e6be5f54872d518efa14303491db Mon Sep 17 00:00:00 2001 From: Josh Story Date: Mon, 19 Aug 2024 11:24:41 -0700 Subject: [PATCH 018/426] [Flight] model halted references explicitly (#30731) using infinitely suspending promises isn't right because this will parse as a promise which is only appropriate if the value we're halting at is a promise. Instead we need to have a special marker type that says this reference will never resolve. Additionally flight client needs to not error any halted references when the stream closes because they will otherwise appear as an error addresses: https://github.com/facebook/react/pull/30705#discussion_r1720479974 --- .../react-client/src/ReactFlightClient.js | 23 ++++ .../src/__tests__/ReactFlightDOM-test.js | 101 ++++++++++++++++++ .../react-server/src/ReactFlightServer.js | 49 ++++----- 3 files changed, 149 insertions(+), 24 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index c386d503bfe6b..68d4ac2cd936c 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -46,6 +46,7 @@ import { enableRefAsProp, enableFlightReadableStream, enableOwnerStacks, + enableHalt, } from 'shared/ReactFeatureFlags'; import { @@ -1986,6 +1987,20 @@ function resolvePostponeDev( } } +function resolveBlocked(response: Response, id: number): void { + const chunks = response._chunks; + const chunk = chunks.get(id); + if (!chunk) { + chunks.set(id, createBlockedChunk(response)); + } else if (chunk.status === PENDING) { + // This chunk as contructed via other means but it is actually a blocked chunk + // so we update it here. We check the status because it might have been aborted + // before we attempted to resolve it. + const blockedChunk: BlockedChunk = (chunk: any); + blockedChunk.status = BLOCKED; + } +} + function resolveHint( response: Response, code: Code, @@ -2612,6 +2627,13 @@ function processFullStringRow( } } // Fallthrough + case 35 /* "#" */: { + if (enableHalt) { + resolveBlocked(response, id); + return; + } + } + // Fallthrough default: /* """ "{" "[" "t" "f" "n" "0" - "9" */ { // We assume anything else is JSON. resolveModel(response, id, row); @@ -2668,6 +2690,7 @@ export function processBinaryChunk( i++; } else if ( (resolvedRowTag > 64 && resolvedRowTag < 91) /* "A"-"Z" */ || + resolvedRowTag === 35 /* "#" */ || resolvedRowTag === 114 /* "r" */ || resolvedRowTag === 120 /* "x" */ ) { diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index 6a0ce0152b704..97fce8a8ea11d 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -2856,4 +2856,105 @@ describe('ReactFlightDOM', () => { jest.advanceTimersByTime('100'); expect(await race).toBe('timeout'); }); + + // @gate enableHalt + it('will halt unfinished chunks inside Suspense when aborting a prerender', async () => { + const controller = new AbortController(); + function ComponentThatAborts() { + controller.abort(); + return null; + } + + async function Greeting() { + await 1; + return 'hello world'; + } + + async function Farewell() { + return 'goodbye world'; + } + + async function Wrapper() { + return ( + + + + ); + } + + function App() { + return ( +
+ + + + + + + +
+ ); + } + + const errors = []; + const {pendingResult} = await serverAct(() => { + return { + pendingResult: ReactServerDOMStaticServer.prerenderToNodeStream( + , + {}, + { + onError(x) { + errors.push(x); + }, + signal: controller.signal, + }, + ), + }; + }); + + controller.abort(); + + const {prelude} = await pendingResult; + expect(errors).toEqual([]); + + const response = ReactServerDOMClient.createFromReadableStream( + Readable.toWeb(prelude), + ); + + const {writable: fizzWritable, readable: fizzReadable} = getTestStream(); + + function ClientApp() { + return use(response); + } + let abortFizz; + await serverAct(async () => { + const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream( + React.createElement(ClientApp), + { + onError(error, errorInfo) { + errors.push(error); + }, + }, + ); + pipe(fizzWritable); + abortFizz = abort; + }); + + await serverAct(() => { + abortFizz('boom'); + }); + + // one error per boundary + expect(errors).toEqual(['boom', 'boom', 'boom']); + + const container = document.createElement('div'); + await readInto(container, fizzReadable); + expect(getMeaningfulChildren(container)).toEqual( +
+ {'loading...'} + {'loading too...'} + {'loading three...'} +
, + ); + }); }); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index bfb12c31c7ffc..c9fe9e3434bb7 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -617,7 +617,7 @@ function serializeThenable( request.abortableTasks.delete(newTask); newTask.status = ABORTED; if (enableHalt && request.fatalError === haltSymbol) { - emitModelChunk(request, newTask.id, reusableInfinitePromiseModel); + emitBlockedChunk(request, newTask.id); } else { const errorId: number = (request.fatalError: any); const model = stringify(serializeByValueID(errorId)); @@ -1820,7 +1820,6 @@ function serializeLazyID(id: number): string { function serializeInfinitePromise(): string { return '$@'; } -const reusableInfinitePromiseModel = stringify(serializeInfinitePromise()); function serializePromiseID(id: number): string { return '$@' + id.toString(16); @@ -2208,9 +2207,6 @@ function renderModel( if (typeof x.then === 'function') { if (request.status === ABORTING) { task.status = ABORTED; - if (enableHalt && request.fatalError === haltSymbol) { - return serializeInfinitePromise(); - } const errorId: number = (request.fatalError: any); if (wasReactNode) { return serializeLazyID(errorId); @@ -2264,9 +2260,6 @@ function renderModel( if (request.status === ABORTING) { task.status = ABORTED; - if (enableHalt && request.fatalError === haltSymbol) { - return serializeInfinitePromise(); - } const errorId: number = (request.fatalError: any); if (wasReactNode) { return serializeLazyID(errorId); @@ -3008,6 +3001,12 @@ function emitPostponeChunk( request.completedErrorChunks.push(processedChunk); } +function emitBlockedChunk(request: Request, id: number): void { + const row = serializeRowHeader('#', id) + '\n'; + const processedChunk = stringToChunk(row); + request.completedErrorChunks.push(processedChunk); +} + function emitErrorChunk( request: Request, id: number, @@ -3757,7 +3756,7 @@ function retryTask(request: Request, task: Task): void { request.abortableTasks.delete(task); task.status = ABORTED; if (enableHalt && request.fatalError === haltSymbol) { - emitModelChunk(request, task.id, reusableInfinitePromiseModel); + emitBlockedChunk(request, task.id); } else { const errorId: number = (request.fatalError: any); const model = stringify(serializeByValueID(errorId)); @@ -3785,7 +3784,7 @@ function retryTask(request: Request, task: Task): void { request.abortableTasks.delete(task); task.status = ABORTED; if (enableHalt && request.fatalError === haltSymbol) { - emitModelChunk(request, task.id, reusableInfinitePromiseModel); + emitBlockedChunk(request, task.id); } else { const errorId: number = (request.fatalError: any); const model = stringify(serializeByValueID(errorId)); @@ -3830,6 +3829,7 @@ function performWork(request: Request): void { currentRequest = request; prepareToUseHooksForRequest(request); + const hadAbortableTasks = request.abortableTasks.size > 0; try { const pingedTasks = request.pingedTasks; request.pingedTasks = []; @@ -3840,10 +3840,11 @@ function performWork(request: Request): void { if (request.destination !== null) { flushCompletedChunks(request, request.destination); } - if (request.abortableTasks.size === 0) { - // we're done rendering - const onAllReady = request.onAllReady; - onAllReady(); + if (hadAbortableTasks && request.abortableTasks.size === 0) { + // We can ping after completing but if this happens there already + // wouldn't be any abortable tasks. So we only call allReady after + // the work which actually completed the last pending task + allReady(request); } } catch (error) { logRecoverableError(request, error, null); @@ -3868,15 +3869,6 @@ function abortTask(task: Task, request: Request, errorId: number): void { request.completedErrorChunks.push(processedChunk); } -function haltTask(task: Task, request: Request): void { - if (task.status === RENDERING) { - // This task will be aborted by the render - return; - } - task.status = ABORTED; - emitModelChunk(request, task.id, reusableInfinitePromiseModel); -} - function flushCompletedChunks( request: Request, destination: Destination, @@ -4055,6 +4047,7 @@ export function abort(request: Request, reason: mixed): void { } abortableTasks.forEach(task => abortTask(task, request, errorId)); abortableTasks.clear(); + allReady(request); } const abortListeners = request.abortListeners; if (abortListeners.size > 0) { @@ -4110,8 +4103,11 @@ export function halt(request: Request, reason: mixed): void { // to that row from every row that's still remaining. if (abortableTasks.size > 0) { request.pendingChunks++; - abortableTasks.forEach(task => haltTask(task, request)); + const errorId = request.nextChunkId++; + emitBlockedChunk(request, errorId); + abortableTasks.forEach(task => abortTask(task, request, errorId)); abortableTasks.clear(); + allReady(request); } const abortListeners = request.abortListeners; if (abortListeners.size > 0) { @@ -4126,3 +4122,8 @@ export function halt(request: Request, reason: mixed): void { fatalError(request, error); } } + +function allReady(request: Request) { + const onAllReady = request.onAllReady; + onAllReady(); +} From 591adfa40d900e9af6d9250f1ae58d72366e7957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 19 Aug 2024 14:51:22 -0400 Subject: [PATCH 019/426] [Flight] Rename Chunk constructor to ReactPromise (#30747) When printing these in DevTools they show up as the name of the constructor so then you pass a Promise to the client it logs as "Chunk" which is confusing. Ideally we'd probably just name this Promise but 1) there's a slight difference in the .then method atm 2) it's a bit tricky to name a variable and get it from the global in the same scope. Closure compiler doesn't let us just name a function because it removes it and just uses the variable name. --- .../react-client/src/ReactFlightClient.js | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 68d4ac2cd936c..6cb9dee4d15de 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -191,7 +191,12 @@ type SomeChunk = | ErroredChunk; // $FlowFixMe[missing-this-annot] -function Chunk(status: any, value: any, reason: any, response: Response) { +function ReactPromise( + status: any, + value: any, + reason: any, + response: Response, +) { this.status = status; this.value = value; this.reason = reason; @@ -201,9 +206,9 @@ function Chunk(status: any, value: any, reason: any, response: Response) { } } // We subclass Promise.prototype so that we get other methods like .catch -Chunk.prototype = (Object.create(Promise.prototype): any); +ReactPromise.prototype = (Object.create(Promise.prototype): any); // TODO: This doesn't return a new Promise chain unlike the real .then -Chunk.prototype.then = function ( +ReactPromise.prototype.then = function ( this: SomeChunk, resolve: (value: T) => mixed, reject?: (reason: mixed) => mixed, @@ -304,12 +309,12 @@ export function getRoot(response: Response): Thenable { function createPendingChunk(response: Response): PendingChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(PENDING, null, null, response); + return new ReactPromise(PENDING, null, null, response); } function createBlockedChunk(response: Response): BlockedChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(BLOCKED, null, null, response); + return new ReactPromise(BLOCKED, null, null, response); } function createErrorChunk( @@ -317,7 +322,7 @@ function createErrorChunk( error: Error | Postpone, ): ErroredChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(ERRORED, null, error, response); + return new ReactPromise(ERRORED, null, error, response); } function wakeChunk(listeners: Array<(T) => mixed>, value: T): void { @@ -391,7 +396,7 @@ function createResolvedModelChunk( value: UninitializedModel, ): ResolvedModelChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(RESOLVED_MODEL, value, null, response); + return new ReactPromise(RESOLVED_MODEL, value, null, response); } function createResolvedModuleChunk( @@ -399,7 +404,7 @@ function createResolvedModuleChunk( value: ClientReference, ): ResolvedModuleChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(RESOLVED_MODULE, value, null, response); + return new ReactPromise(RESOLVED_MODULE, value, null, response); } function createInitializedTextChunk( @@ -407,7 +412,7 @@ function createInitializedTextChunk( value: string, ): InitializedChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(INITIALIZED, value, null, response); + return new ReactPromise(INITIALIZED, value, null, response); } function createInitializedBufferChunk( @@ -415,7 +420,7 @@ function createInitializedBufferChunk( value: $ArrayBufferView | ArrayBuffer, ): InitializedChunk { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(INITIALIZED, value, null, response); + return new ReactPromise(INITIALIZED, value, null, response); } function createInitializedIteratorResultChunk( @@ -424,7 +429,12 @@ function createInitializedIteratorResultChunk( done: boolean, ): InitializedChunk> { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(INITIALIZED, {done: done, value: value}, null, response); + return new ReactPromise( + INITIALIZED, + {done: done, value: value}, + null, + response, + ); } function createInitializedStreamChunk< @@ -437,7 +447,7 @@ function createInitializedStreamChunk< // We use the reason field to stash the controller since we already have that // field. It's a bit of a hack but efficient. // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(INITIALIZED, value, controller, response); + return new ReactPromise(INITIALIZED, value, controller, response); } function createResolvedIteratorResultChunk( @@ -449,7 +459,7 @@ function createResolvedIteratorResultChunk( const iteratorResultJSON = (done ? '{"done":true,"value":' : '{"done":false,"value":') + value + '}'; // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk(RESOLVED_MODEL, iteratorResultJSON, null, response); + return new ReactPromise(RESOLVED_MODEL, iteratorResultJSON, null, response); } function resolveIteratorResultChunk( @@ -1761,7 +1771,7 @@ function startAsyncIterable( if (nextReadIndex === buffer.length) { if (closed) { // $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors - return new Chunk( + return new ReactPromise( INITIALIZED, {done: true, value: undefined}, null, From 52c9c43735d0d5ebb9cd5e2a47c174cb5a5a1713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 19 Aug 2024 15:02:41 -0400 Subject: [PATCH 020/426] [Flight] Emit Infinite Promise as a Halted Row (#30746) Stacked on #30731. When logging a Promise we emit it as an infinite promise instead of blocking the replay on it. This models that as a halted row instead. No need for this special case. I unflag the receiving side since now it's used to replace a feature that's already unflagged so it's used. --- packages/react-client/src/ReactFlightClient.js | 11 ++--------- .../react-client/src/__tests__/ReactFlight-test.js | 12 +++++++++++- packages/react-server/src/ReactFlightServer.js | 9 ++++----- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 6cb9dee4d15de..fbeba4f6c65e2 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -46,7 +46,6 @@ import { enableRefAsProp, enableFlightReadableStream, enableOwnerStacks, - enableHalt, } from 'shared/ReactFeatureFlags'; import { @@ -1194,10 +1193,6 @@ function parseModelString( } case '@': { // Promise - if (value.length === 2) { - // Infinite promise that never resolves. - return new Promise(() => {}); - } const id = parseInt(value.slice(2), 16); const chunk = getChunk(response, id); return chunk; @@ -2638,10 +2633,8 @@ function processFullStringRow( } // Fallthrough case 35 /* "#" */: { - if (enableHalt) { - resolveBlocked(response, id); - return; - } + resolveBlocked(response, id); + return; } // Fallthrough default: /* """ "{" "[" "t" "f" "n" "0" - "9" */ { diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index c3ab6a46805f4..ef457631e3a8c 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -2952,8 +2952,14 @@ describe('ReactFlight', () => { function foo() { return 'hello'; } + function ServerComponent() { - console.log('hi', {prop: 123, fn: foo, map: new Map([['foo', foo]])}); + console.log('hi', { + prop: 123, + fn: foo, + map: new Map([['foo', foo]]), + promise: new Promise(() => {}), + }); throw new Error('err'); } @@ -3018,6 +3024,10 @@ describe('ReactFlight', () => { expect(loggedFn2).not.toBe(foo); expect(loggedFn2.toString()).toBe(foo.toString()); + const promise = mockConsoleLog.mock.calls[0][1].promise; + expect(promise).toBeInstanceOf(Promise); + expect(promise.status).toBe('blocked'); + expect(ownerStacks).toEqual(['\n in App (at **)']); }); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index c9fe9e3434bb7..3680cc715adba 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -1817,10 +1817,6 @@ function serializeLazyID(id: number): string { return '$L' + id.toString(16); } -function serializeInfinitePromise(): string { - return '$@'; -} - function serializePromiseID(id: number): string { return '$@' + id.toString(16); } @@ -3273,7 +3269,10 @@ function renderConsoleValue( } // If it hasn't already resolved (and been instrumented) we just encode an infinite // promise that will never resolve. - return serializeInfinitePromise(); + request.pendingChunks++; + const blockedId = request.nextChunkId++; + emitBlockedChunk(request, blockedId); + return serializePromiseID(blockedId); } if (existingReference !== undefined) { From 0fa9476b9b9b7e284fb6ebe7e1c46a6a6ae85f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 19 Aug 2024 16:34:38 -0400 Subject: [PATCH 021/426] [Flight] Revert Emit Infinite Promise as a Halted Row (#30746) (#30748) This reverts commit 52c9c43735d0d5ebb9cd5e2a47c174cb5a5a1713. Just kidding. We realized we probably don't want to do the halted row thing after all. --- packages/react-client/src/ReactFlightClient.js | 11 +++++++++-- .../react-client/src/__tests__/ReactFlight-test.js | 1 - packages/react-server/src/ReactFlightServer.js | 9 +++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index fbeba4f6c65e2..6cb9dee4d15de 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -46,6 +46,7 @@ import { enableRefAsProp, enableFlightReadableStream, enableOwnerStacks, + enableHalt, } from 'shared/ReactFeatureFlags'; import { @@ -1193,6 +1194,10 @@ function parseModelString( } case '@': { // Promise + if (value.length === 2) { + // Infinite promise that never resolves. + return new Promise(() => {}); + } const id = parseInt(value.slice(2), 16); const chunk = getChunk(response, id); return chunk; @@ -2633,8 +2638,10 @@ function processFullStringRow( } // Fallthrough case 35 /* "#" */: { - resolveBlocked(response, id); - return; + if (enableHalt) { + resolveBlocked(response, id); + return; + } } // Fallthrough default: /* """ "{" "[" "t" "f" "n" "0" - "9" */ { diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index ef457631e3a8c..0c3b8798dc8c3 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -3026,7 +3026,6 @@ describe('ReactFlight', () => { const promise = mockConsoleLog.mock.calls[0][1].promise; expect(promise).toBeInstanceOf(Promise); - expect(promise.status).toBe('blocked'); expect(ownerStacks).toEqual(['\n in App (at **)']); }); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 3680cc715adba..c9fe9e3434bb7 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -1817,6 +1817,10 @@ function serializeLazyID(id: number): string { return '$L' + id.toString(16); } +function serializeInfinitePromise(): string { + return '$@'; +} + function serializePromiseID(id: number): string { return '$@' + id.toString(16); } @@ -3269,10 +3273,7 @@ function renderConsoleValue( } // If it hasn't already resolved (and been instrumented) we just encode an infinite // promise that will never resolve. - request.pendingChunks++; - const blockedId = request.nextChunkId++; - emitBlockedChunk(request, blockedId); - return serializePromiseID(blockedId); + return serializeInfinitePromise(); } if (existingReference !== undefined) { From a960b92cb93e7d006e5e8de850f9b8b51f655c90 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Mon, 19 Aug 2024 19:34:20 -0700 Subject: [PATCH 022/426] [Flight] model halting as never delivered chunks (#30740) stacked on: #30731 We've refined the model of halting a prerender. Now when you abort during a prerender we simply omit the rows that would complete the flight render. This is analagous to prerendering in Fizz where you must resume the prerender to actually result in errors propagating in the postponed holes. We don't have a resume yet for flight and it's not entirely clear how that will work however the key insight here is that deciding whether the never resolving rows are an error or not should really be done on the consuming side rather than in the producer. This PR also reintroduces the logs for the abort error/postpone when prerendering which will give you some indication that something wasn't finished when the prerender was aborted. --- .../react-client/src/ReactFlightClient.js | 22 -- .../src/server/ReactFlightDOMServerNode.js | 22 +- .../src/server/ReactFlightDOMServerBrowser.js | 22 +- .../src/server/ReactFlightDOMServerEdge.js | 22 +- .../src/server/ReactFlightDOMServerNode.js | 22 +- .../src/__tests__/ReactFlightDOM-test.js | 24 +- .../__tests__/ReactFlightDOMBrowser-test.js | 9 +- .../src/__tests__/ReactFlightDOMEdge-test.js | 16 +- .../src/__tests__/ReactFlightDOMNode-test.js | 15 +- .../src/server/ReactFlightDOMServerBrowser.js | 22 +- .../src/server/ReactFlightDOMServerEdge.js | 22 +- .../src/server/ReactFlightDOMServerNode.js | 22 +- .../react-server/src/ReactFlightServer.js | 296 ++++++++++-------- 13 files changed, 253 insertions(+), 283 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 6cb9dee4d15de..072df8108fccd 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -46,7 +46,6 @@ import { enableRefAsProp, enableFlightReadableStream, enableOwnerStacks, - enableHalt, } from 'shared/ReactFeatureFlags'; import { @@ -1997,20 +1996,6 @@ function resolvePostponeDev( } } -function resolveBlocked(response: Response, id: number): void { - const chunks = response._chunks; - const chunk = chunks.get(id); - if (!chunk) { - chunks.set(id, createBlockedChunk(response)); - } else if (chunk.status === PENDING) { - // This chunk as contructed via other means but it is actually a blocked chunk - // so we update it here. We check the status because it might have been aborted - // before we attempted to resolve it. - const blockedChunk: BlockedChunk = (chunk: any); - blockedChunk.status = BLOCKED; - } -} - function resolveHint( response: Response, code: Code, @@ -2637,13 +2622,6 @@ function processFullStringRow( } } // Fallthrough - case 35 /* "#" */: { - if (enableHalt) { - resolveBlocked(response, id); - return; - } - } - // Fallthrough default: /* """ "{" "[" "t" "f" "n" "0" - "9" */ { // We assume anything else is JSON. resolveModel(response, id, row); diff --git a/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js b/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js index 1434d17015a54..a9c978b493012 100644 --- a/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-esm/src/server/ReactFlightDOMServerNode.js @@ -20,15 +20,13 @@ import type {Thenable} from 'shared/ReactTypes'; import {Readable} from 'stream'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -175,35 +173,27 @@ function prerenderToNodeStream( resolve({prelude: readable}); } - const request = createRequest( + const request = createPrerenderRequest( model, moduleBasePath, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js index 56c3d5b71f432..11dbe1a7c1358 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerBrowser.js @@ -12,15 +12,13 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigTurbopackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -134,35 +132,27 @@ function prerender( ); resolve({prelude: stream}); } - const request = createRequest( + const request = createPrerenderRequest( model, turbopackMap, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js index 56c3d5b71f432..11dbe1a7c1358 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerEdge.js @@ -12,15 +12,13 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigTurbopackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -134,35 +132,27 @@ function prerender( ); resolve({prelude: stream}); } - const request = createRequest( + const request = createPrerenderRequest( model, turbopackMap, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js index f9b0c163b2154..9f25004ea4b67 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js @@ -20,15 +20,13 @@ import type {Thenable} from 'shared/ReactTypes'; import {Readable} from 'stream'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -177,35 +175,27 @@ function prerenderToNodeStream( resolve({prelude: readable}); } - const request = createRequest( + const request = createPrerenderRequest( model, turbopackMap, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index 97fce8a8ea11d..aae9cf48c4285 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -2724,7 +2724,7 @@ describe('ReactFlightDOM', () => { }); // @gate enableHalt - it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + it('does not propagate abort reasons errors when aborting a prerender', async () => { let resolveGreeting; const greetingPromise = new Promise(resolve => { resolveGreeting = resolve; @@ -2746,6 +2746,7 @@ describe('ReactFlightDOM', () => { } const controller = new AbortController(); + const errors = []; const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { @@ -2754,15 +2755,20 @@ describe('ReactFlightDOM', () => { webpackMap, { signal: controller.signal, + onError(err) { + errors.push(err); + }, }, ), }; }); - controller.abort(); + controller.abort('boom'); resolveGreeting(); const {prelude} = await pendingResult; + expect(errors).toEqual(['boom']); + const preludeWeb = Readable.toWeb(prelude); const response = ReactServerDOMClient.createFromReadableStream(preludeWeb); @@ -2772,7 +2778,7 @@ describe('ReactFlightDOM', () => { return use(response); } - const errors = []; + errors.length = 0; let abortFizz; await serverAct(async () => { const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream( @@ -2788,10 +2794,10 @@ describe('ReactFlightDOM', () => { }); await serverAct(() => { - abortFizz('boom'); + abortFizz('bam'); }); - expect(errors).toEqual(['boom']); + expect(errors).toEqual(['bam']); const container = document.createElement('div'); await readInto(container, fizzReadable); @@ -2861,7 +2867,7 @@ describe('ReactFlightDOM', () => { it('will halt unfinished chunks inside Suspense when aborting a prerender', async () => { const controller = new AbortController(); function ComponentThatAborts() { - controller.abort(); + controller.abort('boom'); return null; } @@ -2912,11 +2918,8 @@ describe('ReactFlightDOM', () => { }; }); - controller.abort(); - const {prelude} = await pendingResult; - expect(errors).toEqual([]); - + expect(errors).toEqual(['boom']); const response = ReactServerDOMClient.createFromReadableStream( Readable.toWeb(prelude), ); @@ -2926,6 +2929,7 @@ describe('ReactFlightDOM', () => { function ClientApp() { return use(response); } + errors.length = 0; let abortFizz; await serverAct(async () => { const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream( diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index 969f9e125e8c5..a4c5df377be57 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -2402,7 +2402,7 @@ describe('ReactFlightDOMBrowser', () => { }); // @gate enableHalt - it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + it('does not propagate abort reasons errors when aborting a prerender', async () => { let resolveGreeting; const greetingPromise = new Promise(resolve => { resolveGreeting = resolve; @@ -2424,6 +2424,7 @@ describe('ReactFlightDOMBrowser', () => { } const controller = new AbortController(); + const errors = []; const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { @@ -2432,14 +2433,18 @@ describe('ReactFlightDOMBrowser', () => { webpackMap, { signal: controller.signal, + onError(err) { + errors.push(err); + }, }, ), }; }); - controller.abort(); + controller.abort('boom'); resolveGreeting(); const {prelude} = await pendingResult; + expect(errors).toEqual(['boom']); function ClientRoot({response}) { return use(response); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index b38c33dc7761b..1c146014dcefa 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -1103,7 +1103,7 @@ describe('ReactFlightDOMEdge', () => { }); // @gate enableHalt - it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + it('does not propagate abort reasons errors when aborting a prerender', async () => { let resolveGreeting; const greetingPromise = new Promise(resolve => { resolveGreeting = resolve; @@ -1125,6 +1125,7 @@ describe('ReactFlightDOMEdge', () => { } const controller = new AbortController(); + const errors = []; const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { @@ -1133,15 +1134,20 @@ describe('ReactFlightDOMEdge', () => { webpackMap, { signal: controller.signal, + onError(err) { + errors.push(err); + }, }, ), }; }); - controller.abort(); + controller.abort('boom'); resolveGreeting(); const {prelude} = await pendingResult; + expect(errors).toEqual(['boom']); + function ClientRoot({response}) { return use(response); } @@ -1153,7 +1159,7 @@ describe('ReactFlightDOMEdge', () => { }, }); const fizzController = new AbortController(); - const errors = []; + errors.length = 0; const ssrStream = await serverAct(() => ReactDOMServer.renderToReadableStream( React.createElement(ClientRoot, {response}), @@ -1165,8 +1171,8 @@ describe('ReactFlightDOMEdge', () => { }, ), ); - fizzController.abort('boom'); - expect(errors).toEqual(['boom']); + fizzController.abort('bam'); + expect(errors).toEqual(['bam']); // Should still match the result when parsed const result = await readResult(ssrStream); const div = document.createElement('div'); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js index fbe32d2f1f697..620da74ff1db4 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js @@ -443,7 +443,7 @@ describe('ReactFlightDOMNode', () => { }); // @gate enableHalt - it('serializes unfinished tasks with infinite promises when aborting a prerender', async () => { + it('does not propagate abort reasons errors when aborting a prerender', async () => { let resolveGreeting; const greetingPromise = new Promise(resolve => { resolveGreeting = resolve; @@ -465,6 +465,7 @@ describe('ReactFlightDOMNode', () => { } const controller = new AbortController(); + const errors = []; const {pendingResult} = await serverAct(async () => { // destructure trick to avoid the act scope from awaiting the returned value return { @@ -473,14 +474,18 @@ describe('ReactFlightDOMNode', () => { webpackMap, { signal: controller.signal, + onError(err) { + errors.push(err); + }, }, ), }; }); - controller.abort(); + controller.abort('boom'); resolveGreeting(); const {prelude} = await pendingResult; + expect(errors).toEqual(['boom']); function ClientRoot({response}) { return use(response); @@ -492,7 +497,7 @@ describe('ReactFlightDOMNode', () => { moduleLoading: null, }, }); - const errors = []; + errors.length = 0; const ssrStream = await serverAct(() => ReactDOMServer.renderToPipeableStream( React.createElement(ClientRoot, {response}), @@ -503,8 +508,8 @@ describe('ReactFlightDOMNode', () => { }, ), ); - ssrStream.abort('boom'); - expect(errors).toEqual(['boom']); + ssrStream.abort('bam'); + expect(errors).toEqual(['bam']); // Should still match the result when parsed const result = await readResult(ssrStream); const div = document.createElement('div'); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js index 95e7f770428a3..7954417b95a25 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js @@ -12,15 +12,13 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigWebpackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -134,35 +132,27 @@ function prerender( ); resolve({prelude: stream}); } - const request = createRequest( + const request = createPrerenderRequest( model, webpackMap, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js index 95e7f770428a3..7954417b95a25 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerEdge.js @@ -12,15 +12,13 @@ import type {Thenable} from 'shared/ReactTypes'; import type {ClientManifest} from './ReactFlightServerConfigWebpackBundler'; import type {ServerManifest} from 'react-client/src/ReactFlightClientConfig'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -134,35 +132,27 @@ function prerender( ); resolve({prelude: stream}); } - const request = createRequest( + const request = createPrerenderRequest( model, webpackMap, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js index 1d8d6ea9ef743..f459e04914b6e 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightDOMServerNode.js @@ -20,15 +20,13 @@ import type {Thenable} from 'shared/ReactTypes'; import {Readable} from 'stream'; -import {enableHalt} from 'shared/ReactFeatureFlags'; - import { createRequest, + createPrerenderRequest, startWork, startFlowing, stopFlowing, abort, - halt, } from 'react-server/src/ReactFlightServer'; import { @@ -177,35 +175,27 @@ function prerenderToNodeStream( resolve({prelude: readable}); } - const request = createRequest( + const request = createPrerenderRequest( model, webpackMap, + onAllReady, + onFatalError, options ? options.onError : undefined, options ? options.identifierPrefix : undefined, options ? options.onPostpone : undefined, options ? options.temporaryReferences : undefined, __DEV__ && options ? options.environmentName : undefined, __DEV__ && options ? options.filterStackFrame : undefined, - onAllReady, - onFatalError, ); if (options && options.signal) { const signal = options.signal; if (signal.aborted) { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); } else { const listener = () => { const reason = (signal: any).reason; - if (enableHalt) { - halt(request, reason); - } else { - abort(request, reason); - } + abort(request, reason); signal.removeEventListener('abort', listener); }; signal.addEventListener('abort', listener); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index c9fe9e3434bb7..9616d4b972911 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -353,7 +353,8 @@ type Task = { interface Reference {} export type Request = { - status: 0 | 1 | 2 | 3, + status: 10 | 11 | 12 | 13, + type: 20 | 21, flushScheduled: boolean, fatalError: mixed, destination: null | Destination, @@ -425,13 +426,17 @@ function defaultPostponeHandler(reason: string) { // Noop } -const OPEN = 0; -const ABORTING = 1; -const CLOSING = 2; -const CLOSED = 3; +const OPEN = 10; +const ABORTING = 11; +const CLOSING = 12; +const CLOSED = 13; + +const RENDER = 20; +const PRERENDER = 21; function RequestInstance( this: $FlowFixMe, + type: 20 | 21, model: ReactClientValue, bundlerConfig: ClientManifest, onError: void | ((error: mixed) => ?string), @@ -440,8 +445,8 @@ function RequestInstance( temporaryReferences: void | TemporaryReferenceSet, environmentName: void | string | (() => string), // DEV-only filterStackFrame: void | ((url: string, functionName: string) => boolean), // DEV-only - onAllReady: void | (() => void), - onFatalError: void | ((error: mixed) => void), + onAllReady: () => void, + onFatalError: (error: mixed) => void, ) { if ( ReactSharedInternals.A !== null && @@ -466,6 +471,7 @@ function RequestInstance( TaintRegistryPendingRequests.add(cleanupQueue); } const hints = createHints(); + this.type = type; this.status = OPEN; this.flushScheduled = false; this.fatalError = null; @@ -493,8 +499,8 @@ function RequestInstance( this.onError = onError === undefined ? defaultErrorHandler : onError; this.onPostpone = onPostpone === undefined ? defaultPostponeHandler : onPostpone; - this.onAllReady = onAllReady === undefined ? noop : onAllReady; - this.onFatalError = onFatalError === undefined ? noop : onFatalError; + this.onAllReady = onAllReady; + this.onFatalError = onFatalError; if (__DEV__) { this.environmentName = @@ -522,7 +528,7 @@ function RequestInstance( pingedTasks.push(rootTask); } -function noop(): void {} +function noop() {} export function createRequest( model: ReactClientValue, @@ -533,11 +539,38 @@ export function createRequest( temporaryReferences: void | TemporaryReferenceSet, environmentName: void | string | (() => string), // DEV-only filterStackFrame: void | ((url: string, functionName: string) => boolean), // DEV-only - onAllReady: void | (() => void), - onFatalError: void | (() => void), ): Request { // $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors return new RequestInstance( + RENDER, + model, + bundlerConfig, + onError, + identifierPrefix, + onPostpone, + temporaryReferences, + environmentName, + filterStackFrame, + noop, + noop, + ); +} + +export function createPrerenderRequest( + model: ReactClientValue, + bundlerConfig: ClientManifest, + onAllReady: () => void, + onFatalError: () => void, + onError: void | ((error: mixed) => ?string), + identifierPrefix?: string, + onPostpone: void | ((reason: string) => void), + temporaryReferences: void | TemporaryReferenceSet, + environmentName: void | string | (() => string), // DEV-only + filterStackFrame: void | ((url: string, functionName: string) => boolean), // DEV-only +): Request { + // $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors + return new RequestInstance( + PRERENDER, model, bundlerConfig, onError, @@ -616,13 +649,9 @@ function serializeThenable( // We can no longer accept any resolved values request.abortableTasks.delete(newTask); newTask.status = ABORTED; - if (enableHalt && request.fatalError === haltSymbol) { - emitBlockedChunk(request, newTask.id); - } else { - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, newTask.id, model); - } + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, newTask.id, model); return newTask.id; } if (typeof thenable.status === 'string') { @@ -732,7 +761,7 @@ function serializeReadableStream( } if (entry.done) { - request.abortListeners.delete(error); + request.abortListeners.delete(abortStream); const endStreamRow = streamTask.id.toString(16) + ':C\n'; request.completedRegularChunks.push(stringToChunk(endStreamRow)); enqueueFlush(request); @@ -754,34 +783,49 @@ function serializeReadableStream( return; } aborted = true; - request.abortListeners.delete(error); + request.abortListeners.delete(abortStream); + const digest = logRecoverableError(request, reason, streamTask); + emitErrorChunk(request, streamTask.id, digest, reason); + enqueueFlush(request); - let cancelWith: mixed; - if (enableHalt && request.fatalError === haltSymbol) { - cancelWith = reason; - } else if ( + // $FlowFixMe should be able to pass mixed + reader.cancel(reason).then(error, error); + } + function abortStream(reason: mixed) { + if (aborted) { + return; + } + aborted = true; + request.abortListeners.delete(abortStream); + if ( enablePostpone && typeof reason === 'object' && reason !== null && (reason: any).$$typeof === REACT_POSTPONE_TYPE ) { - cancelWith = reason; const postponeInstance: Postpone = (reason: any); logPostpone(request, postponeInstance.message, streamTask); - emitPostponeChunk(request, streamTask.id, postponeInstance); - enqueueFlush(request); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + emitPostponeChunk(request, streamTask.id, postponeInstance); + enqueueFlush(request); + } } else { - cancelWith = reason; const digest = logRecoverableError(request, reason, streamTask); - emitErrorChunk(request, streamTask.id, digest, reason); - enqueueFlush(request); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + emitErrorChunk(request, streamTask.id, digest, reason); + enqueueFlush(request); + } } // $FlowFixMe should be able to pass mixed - reader.cancel(cancelWith).then(error, error); + reader.cancel(reason).then(error, error); } - request.abortListeners.add(error); + request.abortListeners.add(abortStream); reader.read().then(progress, error); return serializeByValueID(streamTask.id); } @@ -837,7 +881,7 @@ function serializeAsyncIterable( } if (entry.done) { - request.abortListeners.delete(error); + request.abortListeners.delete(abortIterable); let endStreamRow; if (entry.value === undefined) { endStreamRow = streamTask.id.toString(16) + ':C\n'; @@ -881,34 +925,52 @@ function serializeAsyncIterable( return; } aborted = true; - request.abortListeners.delete(error); - let throwWith: mixed; - if (enableHalt && request.fatalError === haltSymbol) { - throwWith = reason; - } else if ( + request.abortListeners.delete(abortIterable); + const digest = logRecoverableError(request, reason, streamTask); + emitErrorChunk(request, streamTask.id, digest, reason); + enqueueFlush(request); + if (typeof (iterator: any).throw === 'function') { + // The iterator protocol doesn't necessarily include this but a generator do. + // $FlowFixMe should be able to pass mixed + iterator.throw(reason).then(error, error); + } + } + function abortIterable(reason: mixed) { + if (aborted) { + return; + } + aborted = true; + request.abortListeners.delete(abortIterable); + if ( enablePostpone && typeof reason === 'object' && reason !== null && (reason: any).$$typeof === REACT_POSTPONE_TYPE ) { - throwWith = reason; const postponeInstance: Postpone = (reason: any); logPostpone(request, postponeInstance.message, streamTask); - emitPostponeChunk(request, streamTask.id, postponeInstance); - enqueueFlush(request); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + emitPostponeChunk(request, streamTask.id, postponeInstance); + enqueueFlush(request); + } } else { - throwWith = reason; const digest = logRecoverableError(request, reason, streamTask); - emitErrorChunk(request, streamTask.id, digest, reason); - enqueueFlush(request); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + emitErrorChunk(request, streamTask.id, digest, reason); + enqueueFlush(request); + } } if (typeof (iterator: any).throw === 'function') { // The iterator protocol doesn't necessarily include this but a generator do. // $FlowFixMe should be able to pass mixed - iterator.throw(throwWith).then(error, error); + iterator.throw(reason).then(error, error); } } - request.abortListeners.add(error); + request.abortListeners.add(abortIterable); if (__DEV__) { callIteratorInDEV(iterator, progress, error); } else { @@ -2101,7 +2163,7 @@ function serializeBlob(request: Request, blob: Blob): string { return; } if (entry.done) { - request.abortListeners.delete(error); + request.abortListeners.delete(abortBlob); aborted = true; pingTask(request, newTask); return; @@ -2111,28 +2173,52 @@ function serializeBlob(request: Request, blob: Blob): string { // $FlowFixMe[incompatible-call] return reader.read().then(progress).catch(error); } - function error(reason: mixed) { if (aborted) { return; } aborted = true; - request.abortListeners.delete(error); - let cancelWith: mixed; - if (enableHalt && request.fatalError === haltSymbol) { - cancelWith = reason; + request.abortListeners.delete(abortBlob); + const digest = logRecoverableError(request, reason, newTask); + emitErrorChunk(request, newTask.id, digest, reason); + enqueueFlush(request); + // $FlowFixMe should be able to pass mixed + reader.cancel(reason).then(error, error); + } + function abortBlob(reason: mixed) { + if (aborted) { + return; + } + aborted = true; + request.abortListeners.delete(abortBlob); + if ( + enablePostpone && + typeof reason === 'object' && + reason !== null && + (reason: any).$$typeof === REACT_POSTPONE_TYPE + ) { + const postponeInstance: Postpone = (reason: any); + logPostpone(request, postponeInstance.message, newTask); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + emitPostponeChunk(request, newTask.id, postponeInstance); + enqueueFlush(request); + } } else { - cancelWith = reason; const digest = logRecoverableError(request, reason, newTask); - emitErrorChunk(request, newTask.id, digest, reason); - request.abortableTasks.delete(newTask); - enqueueFlush(request); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + emitErrorChunk(request, newTask.id, digest, reason); + enqueueFlush(request); + } } // $FlowFixMe should be able to pass mixed - reader.cancel(cancelWith).then(error, error); + reader.cancel(reason).then(error, error); } - request.abortListeners.add(error); + request.abortListeners.add(abortBlob); // $FlowFixMe[incompatible-call] reader.read().then(progress).catch(error); @@ -3001,12 +3087,6 @@ function emitPostponeChunk( request.completedErrorChunks.push(processedChunk); } -function emitBlockedChunk(request: Request, id: number): void { - const row = serializeRowHeader('#', id) + '\n'; - const processedChunk = stringToChunk(row); - request.completedErrorChunks.push(processedChunk); -} - function emitErrorChunk( request: Request, id: number, @@ -3755,13 +3835,9 @@ function retryTask(request: Request, task: Task): void { if (request.status === ABORTING) { request.abortableTasks.delete(task); task.status = ABORTED; - if (enableHalt && request.fatalError === haltSymbol) { - emitBlockedChunk(request, task.id); - } else { - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, task.id, model); - } + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, task.id, model); return; } // Something suspended again, let's pick it back up later. @@ -3783,13 +3859,9 @@ function retryTask(request: Request, task: Task): void { if (request.status === ABORTING) { request.abortableTasks.delete(task); task.status = ABORTED; - if (enableHalt && request.fatalError === haltSymbol) { - emitBlockedChunk(request, task.id); - } else { - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, task.id, model); - } + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, task.id, model); return; } @@ -3844,7 +3916,8 @@ function performWork(request: Request): void { // We can ping after completing but if this happens there already // wouldn't be any abortable tasks. So we only call allReady after // the work which actually completed the last pending task - allReady(request); + const onAllReady = request.onAllReady; + onAllReady(); } } catch (error) { logRecoverableError(request, error, null); @@ -4007,17 +4080,17 @@ export function stopFlowing(request: Request): void { request.destination = null; } -// This is called to early terminate a request. It creates an error at all pending tasks. export function abort(request: Request, reason: mixed): void { try { if (request.status === OPEN) { request.status = ABORTING; } const abortableTasks = request.abortableTasks; - // We have tasks to abort. We'll emit one error row and then emit a reference - // to that row from every row that's still remaining. if (abortableTasks.size > 0) { - request.pendingChunks++; + // We have tasks to abort. We'll emit one error row and then emit a reference + // to that row from every row that's still remaining if we are rendering. If we + // are prerendering (and halt semantics are enabled) we will refer to an error row + // but not actually emit it so the reciever can at that point rather than error. const errorId = request.nextChunkId++; request.fatalError = errorId; if ( @@ -4028,7 +4101,11 @@ export function abort(request: Request, reason: mixed): void { ) { const postponeInstance: Postpone = (reason: any); logPostpone(request, postponeInstance.message, null); - emitPostponeChunk(request, errorId, postponeInstance); + if (!enableHalt || request.type === PRERENDER) { + // When prerendering with halt semantics we omit the referred to postpone. + request.pendingChunks++; + emitPostponeChunk(request, errorId, postponeInstance); + } } else { const error = reason === undefined @@ -4043,11 +4120,16 @@ export function abort(request: Request, reason: mixed): void { ) : reason; const digest = logRecoverableError(request, error, null); - emitErrorChunk(request, errorId, digest, error); + if (!enableHalt || request.type === RENDER) { + // When prerendering with halt semantics we omit the referred to error. + request.pendingChunks++; + emitErrorChunk(request, errorId, digest, error); + } } abortableTasks.forEach(task => abortTask(task, request, errorId)); abortableTasks.clear(); - allReady(request); + const onAllReady = request.onAllReady; + onAllReady(); } const abortListeners = request.abortListeners; if (abortListeners.size > 0) { @@ -4087,43 +4169,3 @@ export function abort(request: Request, reason: mixed): void { fatalError(request, error); } } - -const haltSymbol = Symbol('halt'); - -// This is called to stop rendering without erroring. All unfinished work is represented Promises -// that never resolve. -export function halt(request: Request, reason: mixed): void { - try { - if (request.status === OPEN) { - request.status = ABORTING; - } - request.fatalError = haltSymbol; - const abortableTasks = request.abortableTasks; - // We have tasks to abort. We'll emit one error row and then emit a reference - // to that row from every row that's still remaining. - if (abortableTasks.size > 0) { - request.pendingChunks++; - const errorId = request.nextChunkId++; - emitBlockedChunk(request, errorId); - abortableTasks.forEach(task => abortTask(task, request, errorId)); - abortableTasks.clear(); - allReady(request); - } - const abortListeners = request.abortListeners; - if (abortListeners.size > 0) { - abortListeners.forEach(callback => callback(reason)); - abortListeners.clear(); - } - if (request.destination !== null) { - flushCompletedChunks(request, request.destination); - } - } catch (error) { - logRecoverableError(request, error, null); - fatalError(request, error); - } -} - -function allReady(request: Request) { - const onAllReady = request.onAllReady; - onAllReady(); -} From 5997072f691024e0e5afd78c002c0871b1cbd6a6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 20 Aug 2024 11:05:49 -0400 Subject: [PATCH 023/426] [flow] Remove CI_MAX_WORKERS option Noticed this from #30707. This was vestigial from from circleci and now that we're on GH actions I think we should be able to remove this option altogether. ghstack-source-id: 78e8b0243b1e1484ffaad820987ae3679a7374bf Pull Request resolved: https://github.com/facebook/react/pull/30753 --- scripts/flow/config/flowconfig | 1 - scripts/flow/createFlowConfigs.js | 5 ----- 2 files changed, 6 deletions(-) diff --git a/scripts/flow/config/flowconfig b/scripts/flow/config/flowconfig index b2032e0dadcbf..46e7b6e969690 100644 --- a/scripts/flow/config/flowconfig +++ b/scripts/flow/config/flowconfig @@ -33,7 +33,6 @@ untyped-type-import=error [options] -%CI_MAX_WORKERS% munge_underscores=false # Substituted by createFlowConfig.js: diff --git a/scripts/flow/createFlowConfigs.js b/scripts/flow/createFlowConfigs.js index c1e8474160247..7ff68cce5b03a 100644 --- a/scripts/flow/createFlowConfigs.js +++ b/scripts/flow/createFlowConfigs.js @@ -107,11 +107,6 @@ function writeConfig( }); const config = configTemplate - .replace( - '%CI_MAX_WORKERS%\n', - // On CI, we seem to need to limit workers. - process.env.CI ? 'server.max_workers=4\n' : '', - ) .replace('%REACT_RENDERER_FLOW_OPTIONS%', moduleMappings.trim()) .replace('%REACT_RENDERER_FLOW_IGNORES%', ignoredPaths.join('\n')) .replace('%FLOW_VERSION%', flowVersion); From 2505bf9b3400c6a00381e86d30b495935f5339df Mon Sep 17 00:00:00 2001 From: Josh Story Date: Tue, 20 Aug 2024 09:49:41 -0700 Subject: [PATCH 024/426] [Fizz] track postpones when aborting boundaries with a postpone (#30751) When aborting with a postpone value boundaries are put into client rendered mode even during prerenders. This doesn't follow the postpoen semantics of the rest of fizz where during a prerender a postpone is tracked and it will leave holes in tracked postpone state that can be resumed. This change updates this behavior to match the postpones semantics between aborts and imperative postpones. --- .../src/__tests__/ReactDOMFizzServer-test.js | 1 - packages/react-server/src/ReactFizzServer.js | 14 +++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 5d70a0c71ea4d..7d8707bcd3f22 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -7727,7 +7727,6 @@ describe('ReactDOMFizzServer', () => { const prerendered = await pendingPrerender; - expect(prerendered.postponed).toBe(null); expect(errors).toEqual([]); expect(postpones).toEqual(['manufactured', 'manufactured']); diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index 986e8673a5a2a..17c278f2b0b52 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -3857,7 +3857,6 @@ function abortTask(task: Task, request: Request, error: mixed): void { } else { boundary.pendingTasks--; if (boundary.status !== CLIENT_RENDERED) { - boundary.status = CLIENT_RENDERED; // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which // boundary the message is referring to const errorInfo = getThrownInfo(task.componentStack); @@ -3870,11 +3869,24 @@ function abortTask(task: Task, request: Request, error: mixed): void { ) { const postponeInstance: Postpone = (error: any); logPostpone(request, postponeInstance.message, errorInfo, null); + if (request.trackedPostpones !== null && segment !== null) { + trackPostpone(request, request.trackedPostpones, task, segment); + finishedTask(request, task.blockedBoundary, segment); + + // If this boundary was still pending then we haven't already cancelled its fallbacks. + // We'll need to abort the fallbacks, which will also error that parent boundary. + boundary.fallbackAbortableTasks.forEach(fallbackTask => + abortTask(fallbackTask, request, error), + ); + boundary.fallbackAbortableTasks.clear(); + return; + } // TODO: Figure out a better signal than a magic digest value. errorDigest = 'POSTPONE'; } else { errorDigest = logRecoverableError(request, error, errorInfo, null); } + boundary.status = CLIENT_RENDERED; encodeErrorForBoundary(boundary, errorDigest, error, errorInfo, true); untrackBoundary(request, boundary); From 92d26c8e93a88ca41338d3509b4324ad19a89c1e Mon Sep 17 00:00:00 2001 From: Josh Story Date: Tue, 20 Aug 2024 10:22:39 -0700 Subject: [PATCH 025/426] [Flight] When halting omit any reference rather than refer to a shared missing chunk (#30750) When aborting a prerender we should leave references unfulfilled, not share a common unfullfilled reference. functionally today this doesn't matter because we don't have resuming but the semantic is that the row was not available when the abort happened and in a resume the row should fill in. But by pointing each task to a common unfulfilled chunk we lose the ability for these references to resolves to distinct values on resume. --- .../src/__tests__/ReactFlightDOM-test.js | 30 +++- .../__tests__/ReactFlightDOMBrowser-test.js | 20 ++- .../src/__tests__/ReactFlightDOMEdge-test.js | 11 +- .../src/__tests__/ReactFlightDOMNode-test.js | 11 +- .../react-server/src/ReactFlightServer.js | 139 ++++++++++++------ 5 files changed, 153 insertions(+), 58 deletions(-) diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index aae9cf48c4285..41fc0bfd41088 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -2797,7 +2797,16 @@ describe('ReactFlightDOM', () => { abortFizz('bam'); }); - expect(errors).toEqual(['bam']); + if (__DEV__) { + expect(errors).toEqual([new Error('Connection closed.')]); + } else { + // This is likely a bug. In Dev we get a connection closed error + // because the debug info creates a chunk that has a pending status + // and when the stream finishes we error if any chunks are still pending. + // In production there is no debug info so the missing chunk is never instantiated + // because nothing triggers model evaluation before the stream completes + expect(errors).toEqual(['bam']); + } const container = document.createElement('div'); await readInto(container, fizzReadable); @@ -2919,10 +2928,11 @@ describe('ReactFlightDOM', () => { }); const {prelude} = await pendingResult; + expect(errors).toEqual(['boom']); - const response = ReactServerDOMClient.createFromReadableStream( - Readable.toWeb(prelude), - ); + + const preludeWeb = Readable.toWeb(prelude); + const response = ReactServerDOMClient.createFromReadableStream(preludeWeb); const {writable: fizzWritable, readable: fizzReadable} = getTestStream(); @@ -2949,7 +2959,17 @@ describe('ReactFlightDOM', () => { }); // one error per boundary - expect(errors).toEqual(['boom', 'boom', 'boom']); + if (__DEV__) { + const err = new Error('Connection closed.'); + expect(errors).toEqual([err, err, err]); + } else { + // This is likely a bug. In Dev we get a connection closed error + // because the debug info creates a chunk that has a pending status + // and when the stream finishes we error if any chunks are still pending. + // In production there is no debug info so the missing chunk is never instantiated + // because nothing triggers model evaluation before the stream completes + expect(errors).toEqual(['boom', 'boom', 'boom']); + } const container = document.createElement('div'); await readInto(container, fizzReadable); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index a4c5df377be57..fa1e65862564e 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -2454,12 +2454,28 @@ describe('ReactFlightDOMBrowser', () => { passThrough(prelude), ); const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); + errors.length = 0; + const root = ReactDOMClient.createRoot(container, { + onUncaughtError(err) { + errors.push(err); + }, + }); await act(() => { root.render(); }); - expect(container.innerHTML).toBe('
loading...
'); + if (__DEV__) { + expect(errors).toEqual([new Error('Connection closed.')]); + expect(container.innerHTML).toBe(''); + } else { + // This is likely a bug. In Dev we get a connection closed error + // because the debug info creates a chunk that has a pending status + // and when the stream finishes we error if any chunks are still pending. + // In production there is no debug info so the missing chunk is never instantiated + // because nothing triggers model evaluation before the stream completes + expect(errors).toEqual([]); + expect(container.innerHTML).toBe('
loading...
'); + } }); }); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 1c146014dcefa..0cb3897aea443 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -1172,7 +1172,16 @@ describe('ReactFlightDOMEdge', () => { ), ); fizzController.abort('bam'); - expect(errors).toEqual(['bam']); + if (__DEV__) { + expect(errors).toEqual([new Error('Connection closed.')]); + } else { + // This is likely a bug. In Dev we get a connection closed error + // because the debug info creates a chunk that has a pending status + // and when the stream finishes we error if any chunks are still pending. + // In production there is no debug info so the missing chunk is never instantiated + // because nothing triggers model evaluation before the stream completes + expect(errors).toEqual(['bam']); + } // Should still match the result when parsed const result = await readResult(ssrStream); const div = document.createElement('div'); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js index 620da74ff1db4..f2dca4a45c7fa 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js @@ -509,7 +509,16 @@ describe('ReactFlightDOMNode', () => { ), ); ssrStream.abort('bam'); - expect(errors).toEqual(['bam']); + if (__DEV__) { + expect(errors).toEqual([new Error('Connection closed.')]); + } else { + // This is likely a bug. In Dev we get a connection closed error + // because the debug info creates a chunk that has a pending status + // and when the stream finishes we error if any chunks are still pending. + // In production there is no debug info so the missing chunk is never instantiated + // because nothing triggers model evaluation before the stream completes + expect(errors).toEqual(['bam']); + } // Should still match the result when parsed const result = await readResult(ssrStream); const div = document.createElement('div'); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 9616d4b972911..efad2aa59ca81 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -649,9 +649,13 @@ function serializeThenable( // We can no longer accept any resolved values request.abortableTasks.delete(newTask); newTask.status = ABORTED; - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, newTask.id, model); + if (enableHalt && request.type === PRERENDER) { + request.pendingChunks--; + } else { + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, newTask.id, model); + } return newTask.id; } if (typeof thenable.status === 'string') { @@ -1633,6 +1637,24 @@ function outlineTask(request: Request, task: Task): ReactJSONValue { return serializeLazyID(newTask.id); } +function outlineHaltedTask( + request: Request, + task: Task, + allowLazy: boolean, +): ReactJSONValue { + // In the future if we track task state for resuming we'll maybe need to + // construnct an actual task here but since we're never going to retry it + // we just claim the id and serialize it according to the proper convention + const taskId = request.nextChunkId++; + if (allowLazy) { + // We're halting in a position that can handle a lazy reference + return serializeLazyID(taskId); + } else { + // We're halting in a position that needs a value reference + return serializeByValueID(taskId); + } +} + function renderElement( request: Request, task: Task, @@ -2278,6 +2300,20 @@ function renderModel( ((model: any).$$typeof === REACT_ELEMENT_TYPE || (model: any).$$typeof === REACT_LAZY_TYPE); + if (request.status === ABORTING) { + task.status = ABORTED; + if (enableHalt && request.type === PRERENDER) { + // This will create a new task and refer to it in this slot + // the new task won't be retried because we are aborting + return outlineHaltedTask(request, task, wasReactNode); + } + const errorId = (request.fatalError: any); + if (wasReactNode) { + return serializeLazyID(errorId); + } + return serializeByValueID(errorId); + } + const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical @@ -2291,14 +2327,6 @@ function renderModel( if (typeof x === 'object' && x !== null) { // $FlowFixMe[method-unbinding] if (typeof x.then === 'function') { - if (request.status === ABORTING) { - task.status = ABORTED; - const errorId: number = (request.fatalError: any); - if (wasReactNode) { - return serializeLazyID(errorId); - } - return serializeByValueID(errorId); - } // Something suspended, we'll need to create a new task and resolve it later. const newTask = createTask( request, @@ -2344,15 +2372,6 @@ function renderModel( } } - if (request.status === ABORTING) { - task.status = ABORTED; - const errorId: number = (request.fatalError: any); - if (wasReactNode) { - return serializeLazyID(errorId); - } - return serializeByValueID(errorId); - } - // Restore the context. We assume that this will be restored by the inner // functions in case nothing throws so we don't use "finally" here. task.keyPath = prevKeyPath; @@ -3820,6 +3839,22 @@ function retryTask(request: Request, task: Task): void { request.abortableTasks.delete(task); task.status = COMPLETED; } catch (thrownValue) { + if (request.status === ABORTING) { + request.abortableTasks.delete(task); + task.status = ABORTED; + if (enableHalt && request.type === PRERENDER) { + // When aborting a prerener with halt semantics we don't emit + // anything into the slot for a task that aborts, it remains unresolved + request.pendingChunks--; + } else { + // Otherwise we emit an error chunk into the task slot. + const errorId: number = (request.fatalError: any); + const model = stringify(serializeByValueID(errorId)); + emitModelChunk(request, task.id, model); + } + return; + } + const x = thrownValue === SuspenseException ? // This is a special type of exception used for Suspense. For historical @@ -3832,14 +3867,6 @@ function retryTask(request: Request, task: Task): void { if (typeof x === 'object' && x !== null) { // $FlowFixMe[method-unbinding] if (typeof x.then === 'function') { - if (request.status === ABORTING) { - request.abortableTasks.delete(task); - task.status = ABORTED; - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, task.id, model); - return; - } // Something suspended again, let's pick it back up later. task.status = PENDING; task.thenableState = getThenableStateAfterSuspending(); @@ -3856,15 +3883,6 @@ function retryTask(request: Request, task: Task): void { } } - if (request.status === ABORTING) { - request.abortableTasks.delete(task); - task.status = ABORTED; - const errorId: number = (request.fatalError: any); - const model = stringify(serializeByValueID(errorId)); - emitModelChunk(request, task.id, model); - return; - } - request.abortableTasks.delete(task); task.status = ERRORED; const digest = logRecoverableError(request, x, task); @@ -3942,6 +3960,17 @@ function abortTask(task: Task, request: Request, errorId: number): void { request.completedErrorChunks.push(processedChunk); } +function haltTask(task: Task, request: Request): void { + if (task.status === RENDERING) { + // this task will be halted by the render + return; + } + task.status = ABORTED; + // We don't actually emit anything for this task id because we are intentionally + // leaving the reference unfulfilled. + request.pendingChunks--; +} + function flushCompletedChunks( request: Request, destination: Destination, @@ -4087,12 +4116,6 @@ export function abort(request: Request, reason: mixed): void { } const abortableTasks = request.abortableTasks; if (abortableTasks.size > 0) { - // We have tasks to abort. We'll emit one error row and then emit a reference - // to that row from every row that's still remaining if we are rendering. If we - // are prerendering (and halt semantics are enabled) we will refer to an error row - // but not actually emit it so the reciever can at that point rather than error. - const errorId = request.nextChunkId++; - request.fatalError = errorId; if ( enablePostpone && typeof reason === 'object' && @@ -4101,10 +4124,20 @@ export function abort(request: Request, reason: mixed): void { ) { const postponeInstance: Postpone = (reason: any); logPostpone(request, postponeInstance.message, null); - if (!enableHalt || request.type === PRERENDER) { - // When prerendering with halt semantics we omit the referred to postpone. + if (enableHalt && request.type === PRERENDER) { + // When prerendering with halt semantics we simply halt the task + // and leave the reference unfulfilled. + abortableTasks.forEach(task => haltTask(task, request)); + abortableTasks.clear(); + } else { + // When rendering we produce a shared postpone chunk and then + // fulfill each task with a reference to that chunk. + const errorId = request.nextChunkId++; + request.fatalError = errorId; request.pendingChunks++; emitPostponeChunk(request, errorId, postponeInstance); + abortableTasks.forEach(task => abortTask(task, request, errorId)); + abortableTasks.clear(); } } else { const error = @@ -4120,14 +4153,22 @@ export function abort(request: Request, reason: mixed): void { ) : reason; const digest = logRecoverableError(request, error, null); - if (!enableHalt || request.type === RENDER) { - // When prerendering with halt semantics we omit the referred to error. + if (enableHalt && request.type === PRERENDER) { + // When prerendering with halt semantics we simply halt the task + // and leave the reference unfulfilled. + abortableTasks.forEach(task => haltTask(task, request)); + abortableTasks.clear(); + } else { + // When rendering we produce a shared error chunk and then + // fulfill each task with a reference to that chunk. + const errorId = request.nextChunkId++; + request.fatalError = errorId; request.pendingChunks++; emitErrorChunk(request, errorId, digest, error); + abortableTasks.forEach(task => abortTask(task, request, errorId)); + abortableTasks.clear(); } } - abortableTasks.forEach(task => abortTask(task, request, errorId)); - abortableTasks.clear(); const onAllReady = request.onAllReady; onAllReady(); } From 4c2dfb3126f87fc270ad8a07d6180744d25cc585 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Tue, 20 Aug 2024 22:12:23 +0200 Subject: [PATCH 026/426] Ensure `react-dom/client` is built in Codesandbox preview builds (#30757) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4507b9b8e6c65..2bcbda538c964 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "publish-prereleases": "echo 'This command has been deprecated. Please refer to https://github.com/facebook/react/tree/main/scripts/release#trigger-an-automated-prerelease'", "download-build": "node ./scripts/release/download-experimental-build.js", "download-build-for-head": "node ./scripts/release/download-experimental-build.js --commit=$(git rev-parse HEAD)", - "download-build-in-codesandbox-ci": "yarn build --type=node react/index react-dom/index react-dom/src/server react-dom/test-utils scheduler/index react/jsx-runtime react/jsx-dev-runtime", + "download-build-in-codesandbox-ci": "yarn build --type=node react/index react-dom/index react-dom/client react-dom/src/server react-dom/test-utils scheduler/index react/jsx-runtime react/jsx-dev-runtime", "check-release-dependencies": "node ./scripts/release/check-release-dependencies", "generate-inline-fizz-runtime": "node ./scripts/rollup/generate-inline-fizz-runtime.js", "flags": "node ./scripts/flags/flags.js" From 85180b8cf84274795986c8f2c8473f8816db8b7b Mon Sep 17 00:00:00 2001 From: Josh Story Date: Tue, 20 Aug 2024 13:30:51 -0700 Subject: [PATCH 027/426] [Fizz][Static] when aborting a prerender halt unfinished boundaries instead of erroring (#30732) When we introduced prerendering for flight we modeled an abort of a flight prerender as having unfinished rows. This is similar to how postpone was already implemented when you postponed from "within" a prerender using React.unstable_postpone. However when aborting with a postponed instance every boundary would be eagerly marked for client rendering which is more akin to prerendering and then resuming with an aborted signal. The insight with the flight work was that it's not so much the postpone that describes the intended semantics but the abort combined with a prerender. So like in flight when you abort a prerender and enableHalt is enabled boundaries and the shell won't error for any reason. Fizz will still call onPostpone and onError according to the abort reason but the consuemr of the prerender should expect to resume it before trying to use it. --- .../src/__tests__/ReactDOMFizzServer-test.js | 106 ++++++++++++++++++ .../src/__tests__/ReactDOMFizzStatic-test.js | 52 +++++++++ .../ReactDOMFizzStaticBrowser-test.js | 101 +++++++++++++++-- .../__tests__/ReactDOMFizzStaticNode-test.js | 98 ++++++++++++++-- packages/react-server/src/ReactFizzServer.js | 88 ++++++++++++++- 5 files changed, 424 insertions(+), 21 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 7d8707bcd3f22..5a763ffe949ab 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -7746,6 +7746,112 @@ describe('ReactDOMFizzServer', () => { ); }); + // @gate enableHalt + it('can resume a prerender that was aborted', async () => { + const promise = new Promise(r => {}); + + let prerendering = true; + + function Wait() { + if (prerendering) { + return React.use(promise); + } else { + return 'Hello'; + } + } + + function App() { + return ( +
+ +

+ + + + + +

+

+ + + + + +

+
+
+ ); + } + + const controller = new AbortController(); + const signal = controller.signal; + + const errors = []; + function onError(error) { + errors.push(error); + } + let pendingPrerender; + await act(() => { + pendingPrerender = ReactDOMFizzStatic.prerenderToNodeStream(, { + signal, + onError, + }); + }); + controller.abort('boom'); + + const prerendered = await pendingPrerender; + + expect(errors).toEqual(['boom', 'boom']); + + const preludeWritable = new Stream.PassThrough(); + preludeWritable.setEncoding('utf8'); + preludeWritable.on('data', chunk => { + writable.write(chunk); + }); + + await act(() => { + prerendered.prelude.pipe(preludeWritable); + }); + + expect(getVisibleChildren(container)).toEqual( +
+

+ Loading again... +

+

+ Loading again too... +

+
, + ); + + prerendering = false; + + errors.length = 0; + const resumed = await ReactDOMFizzServer.resumeToPipeableStream( + , + JSON.parse(JSON.stringify(prerendered.postponed)), + { + onError, + }, + ); + + await act(() => { + resumed.pipe(writable); + }); + + expect(errors).toEqual([]); + expect(getVisibleChildren(container)).toEqual( +
+

+ Hello +

+

+ Hello +

+
, + ); + }); + // @gate enablePostpone it('does not call onError when you abort with a postpone instance during resume', async () => { let prerendering = true; diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js index 1f3bfa7b3308d..03db4e3f5ed8f 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js @@ -454,4 +454,56 @@ describe('ReactDOMFizzStatic', () => { }); expect(getVisibleChildren(container)).toEqual(undefined); }); + + // @gate enableHalt + it('will halt a prerender when aborting with an error during a render', async () => { + const controller = new AbortController(); + function App() { + controller.abort('sync'); + return
hello world
; + } + + const errors = []; + const result = await ReactDOMFizzStatic.prerenderToNodeStream(, { + signal: controller.signal, + onError(error) { + errors.push(error); + }, + }); + await act(async () => { + result.prelude.pipe(writable); + }); + expect(errors).toEqual(['sync']); + expect(getVisibleChildren(container)).toEqual(undefined); + }); + + // @gate enableHalt + it('will halt a prerender when aborting with an error in a microtask', async () => { + const errors = []; + + const controller = new AbortController(); + function App() { + React.use( + new Promise(() => { + Promise.resolve().then(() => { + controller.abort('async'); + }); + }), + ); + return
hello world
; + } + + errors.length = 0; + const result = await ReactDOMFizzStatic.prerenderToNodeStream(, { + signal: controller.signal, + onError(error) { + errors.push(error); + }, + }); + await act(async () => { + result.prelude.pipe(writable); + }); + expect(errors).toEqual(['async']); + expect(getVisibleChildren(container)).toEqual(undefined); + }); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js index 7a3db48b016e3..357ef1dcb478e 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js @@ -307,7 +307,8 @@ describe('ReactDOMFizzStaticBrowser', () => { }); // @gate experimental - it('should reject if aborting before the shell is complete', async () => { + // @gate !enableHalt + it('should reject if aborting before the shell is complete and enableHalt is disabled', async () => { const errors = []; const controller = new AbortController(); const promise = serverAct(() => @@ -339,6 +340,42 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(errors).toEqual(['aborted for reasons']); }); + // @gate enableHalt + it('should resolve an empty prelude if aborting before the shell is complete', async () => { + const errors = []; + const controller = new AbortController(); + const promise = serverAct(() => + ReactDOMFizzStatic.prerender( +
+ +
, + { + signal: controller.signal, + onError(x) { + errors.push(x.message); + }, + }, + ), + ); + + await jest.runAllTimers(); + + const theReason = new Error('aborted for reasons'); + controller.abort(theReason); + + let rejected = false; + let prelude; + try { + ({prelude} = await promise); + } catch (error) { + rejected = true; + } + expect(rejected).toBe(false); + expect(errors).toEqual(['aborted for reasons']); + const content = await readContent(prelude); + expect(content).toBe(''); + }); + // @gate experimental it('should be able to abort before something suspends', async () => { const errors = []; @@ -365,18 +402,26 @@ describe('ReactDOMFizzStaticBrowser', () => { ), ); - let caughtError = null; - try { - await streamPromise; - } catch (error) { - caughtError = error; + if (gate(flags => flags.enableHalt)) { + const {prelude} = await streamPromise; + const content = await readContent(prelude); + expect(errors).toEqual(['The operation was aborted.']); + expect(content).toBe(''); + } else { + let caughtError = null; + try { + await streamPromise; + } catch (error) { + caughtError = error; + } + expect(caughtError.message).toBe('The operation was aborted.'); + expect(errors).toEqual(['The operation was aborted.']); } - expect(caughtError.message).toBe('The operation was aborted.'); - expect(errors).toEqual(['The operation was aborted.']); }); // @gate experimental - it('should reject if passing an already aborted signal', async () => { + // @gate !enableHalt + it('should reject if passing an already aborted signal and enableHalt is disabled', async () => { const errors = []; const controller = new AbortController(); const theReason = new Error('aborted for reasons'); @@ -410,6 +455,44 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(errors).toEqual(['aborted for reasons']); }); + // @gate enableHalt + it('should resolve an empty prelude if passing an already aborted signal', async () => { + const errors = []; + const controller = new AbortController(); + const theReason = new Error('aborted for reasons'); + controller.abort(theReason); + + const promise = serverAct(() => + ReactDOMFizzStatic.prerender( +
+ Loading
}> + + +
, + { + signal: controller.signal, + onError(x) { + errors.push(x.message); + }, + }, + ), + ); + + // Technically we could still continue rendering the shell but currently the + // semantics mean that we also abort any pending CPU work. + let didThrow = false; + let prelude; + try { + ({prelude} = await promise); + } catch (error) { + didThrow = true; + } + expect(didThrow).toBe(false); + expect(errors).toEqual(['aborted for reasons']); + const content = await readContent(prelude); + expect(content).toBe(''); + }); + // @gate experimental it('supports custom abort reasons with a string', async () => { const promise = new Promise(r => {}); diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js index ade755bdffea1..12ac4de34d684 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzStaticNode-test.js @@ -212,7 +212,8 @@ describe('ReactDOMFizzStaticNode', () => { }); // @gate experimental - it('should reject if aborting before the shell is complete', async () => { + // @gate !enableHalt + it('should reject if aborting before the shell is complete and enableHalt is disabled', async () => { const errors = []; const controller = new AbortController(); const promise = ReactDOMFizzStatic.prerenderToNodeStream( @@ -242,6 +243,40 @@ describe('ReactDOMFizzStaticNode', () => { expect(errors).toEqual(['aborted for reasons']); }); + // @gate enableHalt + it('should resolve an empty shell if aborting before the shell is complete', async () => { + const errors = []; + const controller = new AbortController(); + const promise = ReactDOMFizzStatic.prerenderToNodeStream( +
+ +
, + { + signal: controller.signal, + onError(x) { + errors.push(x.message); + }, + }, + ); + + await jest.runAllTimers(); + + const theReason = new Error('aborted for reasons'); + controller.abort(theReason); + + let didThrow = false; + let prelude; + try { + ({prelude} = await promise); + } catch (error) { + didThrow = true; + } + expect(didThrow).toBe(false); + expect(errors).toEqual(['aborted for reasons']); + const content = await readContent(prelude); + expect(content).toBe(''); + }); + // @gate experimental it('should be able to abort before something suspends', async () => { const errors = []; @@ -266,18 +301,26 @@ describe('ReactDOMFizzStaticNode', () => { }, ); - let caughtError = null; - try { - await streamPromise; - } catch (error) { - caughtError = error; + if (gate(flags => flags.enableHalt)) { + const {prelude} = await streamPromise; + const content = await readContent(prelude); + expect(errors).toEqual(['This operation was aborted']); + expect(content).toBe(''); + } else { + let caughtError = null; + try { + await streamPromise; + } catch (error) { + caughtError = error; + } + expect(caughtError.message).toBe('This operation was aborted'); + expect(errors).toEqual(['This operation was aborted']); } - expect(caughtError.message).toBe('This operation was aborted'); - expect(errors).toEqual(['This operation was aborted']); }); // @gate experimental - it('should reject if passing an already aborted signal', async () => { + // @gate !enableHalt + it('should reject if passing an already aborted signal and enableHalt is disabled', async () => { const errors = []; const controller = new AbortController(); const theReason = new Error('aborted for reasons'); @@ -309,6 +352,43 @@ describe('ReactDOMFizzStaticNode', () => { expect(errors).toEqual(['aborted for reasons']); }); + // @gate enableHalt + it('should resolve with an empty prelude if passing an already aborted signal', async () => { + const errors = []; + const controller = new AbortController(); + const theReason = new Error('aborted for reasons'); + controller.abort(theReason); + + const promise = ReactDOMFizzStatic.prerenderToNodeStream( +
+ Loading
}> + + +
, + { + signal: controller.signal, + onError(x) { + errors.push(x.message); + }, + }, + ); + + // Technically we could still continue rendering the shell but currently the + // semantics mean that we also abort any pending CPU work. + + let didThrow = false; + let prelude; + try { + ({prelude} = await promise); + } catch (error) { + didThrow = true; + } + expect(didThrow).toBe(false); + expect(errors).toEqual(['aborted for reasons']); + const content = await readContent(prelude); + expect(content).toBe(''); + }); + // @gate experimental it('supports custom abort reasons with a string', async () => { const promise = new Promise(r => {}); diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index 17c278f2b0b52..daea492db5b8e 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -157,6 +157,7 @@ import { enableSuspenseAvoidThisFallbackFizz, enableCache, enablePostpone, + enableHalt, enableRenderableContext, enableRefAsProp, disableDefaultPropsExceptForClasses, @@ -3625,6 +3626,9 @@ function erroredTask( ) { // Report the error to a global handler. let errorDigest; + // We don't handle halts here because we only halt when prerendering and + // when prerendering we should be finishing tasks not erroring them when + // they halt or postpone if ( enablePostpone && typeof error === 'object' && @@ -3812,6 +3816,17 @@ function abortTask(task: Task, request: Request, error: mixed): void { logRecoverableError(request, fatal, errorInfo, null); fatalError(request, fatal, errorInfo, null); } + } else if ( + enableHalt && + request.trackedPostpones !== null && + segment !== null + ) { + const trackedPostpones = request.trackedPostpones; + // We are aborting a prerender and must treat the shell as halted + // We log the error but we still resolve the prerender + logRecoverableError(request, error, errorInfo, null); + trackPostpone(request, trackedPostpones, task, segment); + finishedTask(request, null, segment); } else { logRecoverableError(request, error, errorInfo, null); fatalError(request, error, errorInfo, null); @@ -3856,10 +3871,40 @@ function abortTask(task: Task, request: Request, error: mixed): void { } } else { boundary.pendingTasks--; + // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which + // boundary the message is referring to + const errorInfo = getThrownInfo(task.componentStack); + const trackedPostpones = request.trackedPostpones; if (boundary.status !== CLIENT_RENDERED) { - // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which - // boundary the message is referring to - const errorInfo = getThrownInfo(task.componentStack); + if (enableHalt) { + if (trackedPostpones !== null && segment !== null) { + // We are aborting a prerender + if ( + enablePostpone && + typeof error === 'object' && + error !== null && + error.$$typeof === REACT_POSTPONE_TYPE + ) { + const postponeInstance: Postpone = (error: any); + logPostpone(request, postponeInstance.message, errorInfo, null); + } else { + // We are aborting a prerender and must halt this boundary. + // We treat this like other postpones during prerendering + logRecoverableError(request, error, errorInfo, null); + } + trackPostpone(request, trackedPostpones, task, segment); + // If this boundary was still pending then we haven't already cancelled its fallbacks. + // We'll need to abort the fallbacks, which will also error that parent boundary. + boundary.fallbackAbortableTasks.forEach(fallbackTask => + abortTask(fallbackTask, request, error), + ); + boundary.fallbackAbortableTasks.clear(); + return finishedTask(request, boundary, segment); + } + } + boundary.status = CLIENT_RENDERED; + // We are aborting a render or resume which should put boundaries + // into an explicitly client rendered state let errorDigest; if ( enablePostpone && @@ -4145,6 +4190,43 @@ function retryRenderTask( ? request.fatalError : thrownValue; + if ( + enableHalt && + request.status === ABORTING && + request.trackedPostpones !== null + ) { + // We are aborting a prerender and need to halt this task. + const trackedPostpones = request.trackedPostpones; + const thrownInfo = getThrownInfo(task.componentStack); + task.abortSet.delete(task); + + if ( + enablePostpone && + typeof x === 'object' && + x !== null && + x.$$typeof === REACT_POSTPONE_TYPE + ) { + const postponeInstance: Postpone = (x: any); + logPostpone( + request, + postponeInstance.message, + thrownInfo, + __DEV__ && enableOwnerStacks ? task.debugTask : null, + ); + } else { + logRecoverableError( + request, + x, + thrownInfo, + __DEV__ && enableOwnerStacks ? task.debugTask : null, + ); + } + + trackPostpone(request, trackedPostpones, task, segment); + finishedTask(request, task.blockedBoundary, segment); + return; + } + if (typeof x === 'object' && x !== null) { // $FlowFixMe[method-unbinding] if (typeof x.then === 'function') { From e831c232787400474673051d63df4aaf6c01bdeb Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 20 Aug 2024 16:40:01 -0400 Subject: [PATCH 028/426] Test infra: Support gate('enableFeatureFlag') (#30760) Shortcut for the common case where only a single flag is checked. Same as `gate(flags => flags.enableFeatureFlag)`. Normally I don't care about these types of conveniences but I'm about to add a lot more inline flag checks these all over our tests and it gets noisy. This helps a bit. --- .../transform-test-gate-pragma-test.js | 4 ++++ scripts/jest/setupTests.js | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/scripts/babel/__tests__/transform-test-gate-pragma-test.js b/scripts/babel/__tests__/transform-test-gate-pragma-test.js index f4abf54bec0e2..6250b5b4ded16 100644 --- a/scripts/babel/__tests__/transform-test-gate-pragma-test.js +++ b/scripts/babel/__tests__/transform-test-gate-pragma-test.js @@ -221,4 +221,8 @@ describe('dynamic gate method', () => { it('returns same conditions as pragma', () => { expect(gate(ctx => ctx.experimental && ctx.__DEV__)).toBe(true); }); + + it('converts string conditions to accessor function', () => { + expect(gate('experimental')).toBe(gate(flags => flags.experimental)); + }); }); diff --git a/scripts/jest/setupTests.js b/scripts/jest/setupTests.js index 722df83f19533..d339c86433a41 100644 --- a/scripts/jest/setupTests.js +++ b/scripts/jest/setupTests.js @@ -205,8 +205,17 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) { } }; + const coerceGateConditionToFunction = gateFnOrString => { + return typeof gateFnOrString === 'string' + ? // `gate('foo')` is treated as equivalent to `gate(flags => flags.foo)` + flags => flags[gateFnOrString] + : // Assume this is already a function + gateFnOrString; + }; + const gatedErrorMessage = 'Gated test was expected to fail, but it passed.'; - global._test_gate = (gateFn, testName, callback, timeoutMS) => { + global._test_gate = (gateFnOrString, testName, callback, timeoutMS) => { + const gateFn = coerceGateConditionToFunction(gateFnOrString); let shouldPass; try { const flags = getTestFlags(); @@ -230,7 +239,8 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) { expectTestToFail(callback, error, timeoutMS)); } }; - global._test_gate_focus = (gateFn, testName, callback, timeoutMS) => { + global._test_gate_focus = (gateFnOrString, testName, callback, timeoutMS) => { + const gateFn = coerceGateConditionToFunction(gateFnOrString); let shouldPass; try { const flags = getTestFlags(); @@ -259,8 +269,9 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) { }; // Dynamic version of @gate pragma - global.gate = fn => { + global.gate = gateFnOrString => { + const gateFn = coerceGateConditionToFunction(gateFnOrString); const flags = getTestFlags(); - return fn(flags); + return gateFn(flags); }; } From dc32c7f35ed6699e302dc7dbae17804555c669c6 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Tue, 20 Aug 2024 21:43:21 -0700 Subject: [PATCH 029/426] [Flight] use microtask for scheduling during prerenders (#30768) In https://github.com/facebook/react/pull/29491 I updated the work scheduler for Flight to use microtasks to perform work when something pings. This is useful but it does have some downsides in terms of our ability to do task prioritization. Additionally the initial work is not instantiated using a microtask which is inconsistent with how pings work. In this change I update the scheduling logic to use microtasks consistently for prerenders and use regular tasks for renders both for the initial work and pings. --- .../ReactInternalTestUtils.js | 2 +- packages/internal-test-utils/internalAct.js | 87 +++++++++++++++++++ .../src/__tests__/ReactFlightDOMEdge-test.js | 9 +- .../react-server/src/ReactFlightServer.js | 24 ++++- 4 files changed, 109 insertions(+), 13 deletions(-) diff --git a/packages/internal-test-utils/ReactInternalTestUtils.js b/packages/internal-test-utils/ReactInternalTestUtils.js index 4d2fa37890850..317a07262c5ad 100644 --- a/packages/internal-test-utils/ReactInternalTestUtils.js +++ b/packages/internal-test-utils/ReactInternalTestUtils.js @@ -16,7 +16,7 @@ import { clearErrors, createLogAssertion, } from './consoleMock'; -export {act} from './internalAct'; +export {act, serverAct} from './internalAct'; const {assertConsoleLogsCleared} = require('internal-test-utils/consoleMock'); import {thrownErrors, actingUpdatesScopeDepth} from './internalAct'; diff --git a/packages/internal-test-utils/internalAct.js b/packages/internal-test-utils/internalAct.js index 22bb92c24fc26..66fa324984507 100644 --- a/packages/internal-test-utils/internalAct.js +++ b/packages/internal-test-utils/internalAct.js @@ -192,3 +192,90 @@ export async function act(scope: () => Thenable): Thenable { } } } + +export async function serverAct(scope: () => Thenable): Thenable { + // We require every `act` call to assert console logs + // with one of the assertion helpers. Fails if not empty. + assertConsoleLogsCleared(); + + // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object + if (!jest.isMockFunction(setTimeout)) { + throw Error( + "This version of `act` requires Jest's timer mocks " + + '(i.e. jest.useFakeTimers).', + ); + } + + // Create the error object before doing any async work, to get a better + // stack trace. + const error = new Error(); + Error.captureStackTrace(error, act); + + // Call the provided scope function after an async gap. This is an extra + // precaution to ensure that our tests do not accidentally rely on the act + // scope adding work to the queue synchronously. We don't do this in the + // public version of `act`, though we maybe should in the future. + await waitForMicrotasks(); + + const errorHandlerNode = function (err: mixed) { + thrownErrors.push(err); + }; + // We track errors that were logged globally as if they occurred in this scope and then rethrow them. + if (typeof process === 'object') { + // Node environment + process.on('uncaughtException', errorHandlerNode); + } else if ( + typeof window === 'object' && + typeof window.addEventListener === 'function' + ) { + throw new Error('serverAct is not supported in JSDOM environments'); + } + + try { + const result = await scope(); + + do { + // Wait until end of current task/microtask. + await waitForMicrotasks(); + + // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object + if (jest.isEnvironmentTornDown()) { + error.message = + 'The Jest environment was torn down before `act` completed. This ' + + 'probably means you forgot to `await` an `act` call.'; + throw error; + } + + // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object + const j = jest; + if (j.getTimerCount() > 0) { + // There's a pending timer. Flush it now. We only do this in order to + // force Suspense fallbacks to display; the fact that it's a timer + // is an implementation detail. If there are other timers scheduled, + // those will also fire now, too, which is not ideal. (The public + // version of `act` doesn't do this.) For this reason, we should try + // to avoid using timers in our internal tests. + j.runOnlyPendingTimers(); + // If a committing a fallback triggers another update, it might not + // get scheduled until a microtask. So wait one more time. + await waitForMicrotasks(); + } else { + break; + } + } while (true); + + if (thrownErrors.length > 0) { + // Rethrow any errors logged by the global error handling. + const thrownError = aggregateErrors(thrownErrors); + thrownErrors.length = 0; + throw thrownError; + } + + return result; + } finally { + if (typeof process === 'object') { + // Node environment + process.off('uncaughtException', errorHandlerNode); + } + } +} diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 0cb3897aea443..27dbcc067e91a 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -23,10 +23,6 @@ if (typeof File === 'undefined' || typeof FormData === 'undefined') { // Patch for Edge environments for global scope global.AsyncLocalStorage = require('async_hooks').AsyncLocalStorage; -const { - patchMessageChannel, -} = require('../../../../scripts/jest/patchMessageChannel'); - let serverExports; let clientExports; let webpackMap; @@ -39,7 +35,6 @@ let ReactServerDOMServer; let ReactServerDOMStaticServer; let ReactServerDOMClient; let use; -let ReactServerScheduler; let reactServerAct; function normalizeCodeLocInfo(str) { @@ -55,9 +50,7 @@ describe('ReactFlightDOMEdge', () => { beforeEach(() => { jest.resetModules(); - ReactServerScheduler = require('scheduler'); - patchMessageChannel(ReactServerScheduler); - reactServerAct = require('internal-test-utils').act; + reactServerAct = require('internal-test-utils').serverAct; // Simulate the condition resolution jest.mock('react', () => require('react/react.react-server')); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index efad2aa59ca81..df811a8c7fa99 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -1794,7 +1794,11 @@ function pingTask(request: Request, task: Task): void { pingedTasks.push(task); if (pingedTasks.length === 1) { request.flushScheduled = request.destination !== null; - scheduleMicrotask(() => performWork(request)); + if (request.type === PRERENDER) { + scheduleMicrotask(() => performWork(request)); + } else { + scheduleWork(() => performWork(request)); + } } } @@ -4056,10 +4060,20 @@ function flushCompletedChunks( export function startWork(request: Request): void { request.flushScheduled = request.destination !== null; - if (supportsRequestStorage) { - scheduleWork(() => requestStorage.run(request, performWork, request)); + if (request.type === PRERENDER) { + if (supportsRequestStorage) { + scheduleMicrotask(() => { + requestStorage.run(request, performWork, request); + }); + } else { + scheduleMicrotask(() => performWork(request)); + } } else { - scheduleWork(() => performWork(request)); + if (supportsRequestStorage) { + scheduleWork(() => requestStorage.run(request, performWork, request)); + } else { + scheduleWork(() => performWork(request)); + } } } @@ -4073,6 +4087,8 @@ function enqueueFlush(request: Request): void { request.destination !== null ) { request.flushScheduled = true; + // Unlike startWork and pingTask we intetionally use scheduleWork + // here even during prerenders to allow as much batching as possible scheduleWork(() => { request.flushScheduled = false; const destination = request.destination; From dd9117e3134f24d1aa39e405a95ab54188a017dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 21 Aug 2024 09:52:17 -0400 Subject: [PATCH 030/426] [Flight] Source Map Actions in Reference Node Loader Transforms (#30755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow up to #30741. This is just for the reference Webpack implementation. If there is a source map associated with a Node ESM loader, we generate new source map entries for every `registerServerReference` call. To avoid messing too much with it, this doesn't rewrite the original mappings. It just reads them while finding each of the exports in the original mappings. We need to read all since whatever we append at the end is relative. Then we just generate new appended entries at the end. For the location I picked the location of the local name identifier. Since that's the name of the function and that gives us a source map name index. It means it jumps to the name rather than the beginning of the function declaration. It could be made more clever like finding a local function definition if it is reexported. We could also point to the line/column of the function declaration rather than the identifier but point to the name index of the identifier name. Now jumping to definition works in the fixture. Screenshot 2024-08-20 at 2 49 07 PM Unfortunately this technique doesn't seem to work in Firefox nor Safari. They don't apply the source map for jumping to the definition. --- fixtures/flight/package.json | 1 + fixtures/flight/yarn.lock | 2166 +++++++++++------ .../react-server-dom-webpack/package.json | 3 +- .../src/ReactFlightWebpackNodeLoader.js | 403 ++- scripts/rollup/modules.js | 3 + yarn.lock | 12 +- 6 files changed, 1780 insertions(+), 808 deletions(-) diff --git a/fixtures/flight/package.json b/fixtures/flight/package.json index a0505629baacf..f9b8a752d4f83 100644 --- a/fixtures/flight/package.json +++ b/fixtures/flight/package.json @@ -49,6 +49,7 @@ "react-dev-utils": "^12.0.1", "react-dom": "experimental", "react-refresh": "^0.11.0", + "react-server-dom-webpack": "experimental", "resolve": "^1.20.0", "resolve-url-loader": "^4.0.0", "sass-loader": "^12.3.0", diff --git a/fixtures/flight/yarn.lock b/fixtures/flight/yarn.lock index 927f680a6ca10..36e16f18a9984 100644 --- a/fixtures/flight/yarn.lock +++ b/fixtures/flight/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.2.tgz#a6abc715fb6884851fca9dad37fc34739a04fd11" integrity sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw== +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -2379,6 +2384,23 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36" integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg== +"@fastify/busboy@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" + integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -2620,7 +2642,7 @@ "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": +"@jridgewell/gen-mapping@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== @@ -2629,36 +2651,52 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/source-map@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" - integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.15" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" - integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@^0.3.17": version "0.3.18" @@ -2668,6 +2706,22 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -2689,6 +2743,11 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@playwright/test@^1.41.2": version "1.41.2" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.41.2.tgz#bd9db40177f8fd442e16e14e0389d23751cdfc54" @@ -2960,10 +3019,10 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== -"@types/estree@^0.0.51": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== +"@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== "@types/graceful-fs@^4.1.2": version "4.1.4" @@ -3092,125 +3151,125 @@ dependencies: "@types/yargs-parser" "*" -"@webassemblyjs/ast@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" - integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== dependencies: - "@webassemblyjs/helper-numbers" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" -"@webassemblyjs/floating-point-hex-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" - integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== -"@webassemblyjs/helper-api-error@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" - integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== -"@webassemblyjs/helper-buffer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" - integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== -"@webassemblyjs/helper-numbers@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" - integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" - integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/helper-wasm-section@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" - integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" -"@webassemblyjs/ieee754@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" - integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" - integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" - integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== - -"@webassemblyjs/wasm-edit@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" - integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/helper-wasm-section" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-opt" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - "@webassemblyjs/wast-printer" "1.11.1" - -"@webassemblyjs/wasm-gen@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" - integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - -"@webassemblyjs/wasm-opt@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" - integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-buffer" "1.11.1" - "@webassemblyjs/wasm-gen" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" - -"@webassemblyjs/wasm-parser@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" - integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== - dependencies: - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/helper-api-error" "1.11.1" - "@webassemblyjs/helper-wasm-bytecode" "1.11.1" - "@webassemblyjs/ieee754" "1.11.1" - "@webassemblyjs/leb128" "1.11.1" - "@webassemblyjs/utf8" "1.11.1" - -"@webassemblyjs/wast-printer@1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" - integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== - dependencies: - "@webassemblyjs/ast" "1.11.1" +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -3231,11 +3290,6 @@ abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - accepts@~1.3.5: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -3252,31 +3306,34 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" -acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== -acorn-node@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== +acorn-loose@^8.3.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/acorn-loose/-/acorn-loose-8.4.0.tgz#26d3e219756d1e180d006f5bcc8d261a28530f55" + integrity sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ== dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" + acorn "^8.11.0" -acorn-walk@^7.0.0, acorn-walk@^7.1.1: +acorn-walk@^7.1.1: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn@^7.0.0, acorn@^7.1.1: +acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4, acorn@^8.5.0, acorn@^8.7.1: +acorn@^8.11.0, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +acorn@^8.2.4, acorn@^8.7.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== @@ -3321,7 +3378,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv-keywords@^5.0.0, ajv-keywords@^5.1.0: +ajv-keywords@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== @@ -3338,7 +3395,7 @@ ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.8.0: +ajv@^8.0.0: version "8.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== @@ -3381,15 +3438,6 @@ ansi-html@^0.0.9: resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.9.tgz#6512d02342ae2cc68131952644a129cb734cd3f0" integrity sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg== -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -3418,6 +3466,16 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + anymatch@^3.0.3: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" @@ -3450,11 +3508,46 @@ aria-query@^5.0.0: resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c" integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array.prototype.reduce@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz#6aadc2f995af29cb887eb866d981dc85ab6f7dc7" + integrity sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-array-method-boxes-properly "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + is-string "^1.0.7" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -3476,6 +3569,13 @@ autoprefixer@^10.4.8: picocolors "^1.0.0" postcss-value-parser "^4.2.0" +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + babel-jest@^27.4.2, babel-jest@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" @@ -3686,7 +3786,14 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2, braces@~3.0.2: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -3706,17 +3813,6 @@ browserslist@^4.0.0: electron-to-chromium "^1.3.73" node-releases "^1.0.0-alpha.12" -browserslist@^4.14.5: - version "4.15.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.15.0.tgz#3d48bbca6a3f378e86102ffd017d9a03f122bdb0" - integrity sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ== - dependencies: - caniuse-lite "^1.0.30001164" - colorette "^1.2.1" - electron-to-chromium "^1.3.612" - escalade "^3.1.1" - node-releases "^1.1.67" - browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^4.20.3, browserslist@^4.21.3: version "4.21.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" @@ -3727,6 +3823,16 @@ browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^ node-releases "^2.0.6" update-browserslist-db "^1.0.5" +browserslist@^4.21.10, browserslist@^4.21.4: + version "4.23.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" + integrity sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA== + dependencies: + caniuse-lite "^1.0.30001646" + electron-to-chromium "^1.5.4" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + browserslist@^4.21.5: version "4.21.9" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635" @@ -3772,6 +3878,17 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.0" +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -3813,7 +3930,7 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000888, caniuse-lite@^1.0.30001164, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001373: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000888, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001373: version "1.0.30001457" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001457.tgz" integrity sha512-SDIV6bgE1aVbK6XyxdURbUE89zY7+k1BBBaOwYwkNCglXlel/E7mELiHC64HQ+W0xSKlqWhV9Wh7iHxUjMs4fA== @@ -3823,6 +3940,11 @@ caniuse-lite@^1.0.30001503: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001505.tgz#10a343e49d31cbbfdae298ef73cb0a9f46670dc5" integrity sha512-jaAOR5zVtxHfL0NjZyflVTtXm3D3J9P15zSJ7HmQF8dSKGA6tqzQq+0ZI3xkjyQj46I4/M0K2GbMpcAFOcbr3A== +caniuse-lite@^1.0.30001646: + version "1.0.30001651" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" + integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== + case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" @@ -3917,6 +4039,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -3951,7 +4082,7 @@ color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" -color-name@^1.1.4, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -3960,11 +4091,6 @@ colord@^2.9.1: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== -colorette@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" - integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== - colorette@^2.0.10: version "2.0.19" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" @@ -3981,6 +4107,11 @@ commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" @@ -4092,7 +4223,7 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -4307,6 +4438,33 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + date-fns@^2.16.1: version "2.29.1" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.1.tgz#9667c2615525e552b5135a3116b95b1961456e60" @@ -4358,6 +4516,15 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" @@ -4369,10 +4536,14 @@ define-properties@^1.1.2, define-properties@^1.1.3: dependencies: object-keys "^1.0.12" -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ== +define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" delayed-stream@~1.0.0: version "1.0.0" @@ -4401,15 +4572,6 @@ detect-port-alt@^1.1.6: address "^1.0.1" debug "^2.6.0" -detective@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" - integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw== - dependencies: - acorn-node "^1.8.2" - defined "^1.0.0" - minimist "^1.2.6" - didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" @@ -4531,15 +4693,15 @@ duplexer@^0.1.2: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.612: - version "1.3.617" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.617.tgz#4192fa4db846c6ad51fffe3a06e71727e9699a74" - integrity sha512-yHXyI0fHnU0oLxdu21otLYpW3qwkbo8EBTpqeS9w14fwNjFy65SG6unrS3Gg+wX1JKWlAFCcNt13fG0nsCo/1A== - electron-to-chromium@^1.3.73: version "1.3.73" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.73.tgz#aa67787067d58cc3920089368b3b8d6fe0fc12f6" @@ -4554,6 +4716,11 @@ electron-to-chromium@^1.4.431: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.435.tgz#761c34300603b9f1234f0b6155870d3002435db6" integrity sha512-B0CBWVFhvoQCW/XtjRzgrmqcgVWg6RXOEM/dK59+wFV93BFGR6AeNKc4OyhM+T3IhJaOOG8o/V+33Y2mwJWtzw== +electron-to-chromium@^1.5.4: + version "1.5.12" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.12.tgz#ee31756eaa2e06f2aa606f170b7ad06dd402b4e4" + integrity sha512-tIhPkdlEoCL1Y+PToq3zRNehUaKp3wBX/sr7aclAWdIWjvqAe/Im/H0SiCM4c1Q8BLPHCdoJTol+ZblflydehA== + emittery@^0.10.2: version "0.10.2" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" @@ -4568,15 +4735,20 @@ emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== -enhanced-resolve@^5.10.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" - integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== +enhanced-resolve@^5.17.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -4618,22 +4790,97 @@ es-abstract@^1.12.0: string.prototype.trimleft "^2.1.0" string.prototype.trimright "^2.1.0" -es-abstract@^1.5.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" +es-abstract@^1.17.2, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: - es-to-primitive "^1.1.1" - function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" - is-regex "^1.0.4" + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -es-module-lexer@^0.9.0: - version "0.9.3" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" - integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== +es-module-lexer@^1.2.1: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -es-to-primitive@^1.1.1, es-to-primitive@^1.2.0: +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-to-primitive@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" dependencies: @@ -4641,11 +4888,25 @@ es-to-primitive@^1.1.1, es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -4754,7 +5015,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.9: +fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== @@ -4765,6 +5026,17 @@ fast-glob@^3.2.11, fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -4839,6 +5111,21 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + fork-ts-checker-webpack-plugin@^6.5.0: version "6.5.2" resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz#4f67183f2f9eb8ba7df7177ce3cf3e75cdafb340" @@ -4909,6 +5196,26 @@ function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4928,14 +5235,16 @@ get-intrinsic@^1.0.0: has "^1.0.3" has-symbols "^1.0.1" -get-intrinsic@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" - integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-package-type@^0.1.0: version "0.1.0" @@ -4947,6 +5256,15 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -4966,6 +5284,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.1.1, glob@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -5007,6 +5337,14 @@ globals@^11.1.0: version "11.8.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.8.0.tgz#c1ef45ee9bed6badf0663c5cb90e8d1adec1321d" +globalthis@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + globby@^11.0.4: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -5019,6 +5357,13 @@ globby@^11.0.4: merge2 "^1.4.1" slash "^3.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -5027,6 +5372,11 @@ graceful-fs@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" +graceful-fs@^4.2.11: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" @@ -5048,6 +5398,11 @@ harmony-reflect@^1.4.6: version "1.6.1" resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.1.tgz#c108d4f2bb451efef7a37861fdbdae72c9bdefa9" +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -5057,6 +5412,18 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + has-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" @@ -5066,17 +5433,31 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== -has-symbols@^1.0.3: +has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: function-bind "^1.1.1" +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -5255,10 +5636,34 @@ ini@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -5266,30 +5671,36 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-callable@^1.1.3, is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" -is-core-module@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" - integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== - dependencies: - has "^1.0.3" +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" - integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== +is-core-module@^2.13.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: - has "^1.0.3" + hasown "^2.0.2" -is-core-module@^2.9.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" - integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== dependencies: - has "^1.0.3" + is-typed-array "^1.1.13" is-date-object@^1.0.1: version "1.0.1" @@ -5330,6 +5741,18 @@ is-glob@^4.0.3: dependencies: is-extglob "^2.1.1" +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -5346,27 +5769,70 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-root@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + is-symbol@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" dependencies: has-symbols "^1.0.0" +is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -5374,6 +5840,11 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5425,6 +5896,15 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-changed-files@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" @@ -5914,7 +6394,12 @@ jest@^27.4.3: import-local "^3.0.2" jest-cli "^27.5.1" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +jiti@^1.21.0: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== + +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -6024,11 +6509,21 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lilconfig@^2.0.3, lilconfig@^2.0.5, lilconfig@^2.0.6: +lilconfig@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lilconfig@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -6083,10 +6578,6 @@ lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -6109,12 +6600,6 @@ lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -loose-envify@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -6122,6 +6607,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -6129,13 +6619,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - lz-string@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" @@ -6148,11 +6631,12 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" mdn-data@2.0.14: version "2.0.14" @@ -6191,6 +6675,14 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +micromatch@^4.0.5: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -6219,20 +6711,34 @@ mini-css-extract-plugin@^2.4.5: dependencies: schema-utils "^4.0.0" -minimatch@3.0.4, minimatch@^3.0.4: +minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" +minimatch@^3.0.5: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== mkdirp@~0.5.1: version "0.5.1" @@ -6253,11 +6759,25 @@ ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -6267,7 +6787,7 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -neo-async@^2.6.2: +neo-async@^2.6.1, neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -6290,16 +6810,16 @@ node-releases@^1.0.0-alpha.12: dependencies: semver "^5.3.0" -node-releases@^1.1.67: - version "1.1.67" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12" - integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg== - node-releases@^2.0.12: version "2.0.12" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + node-releases@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" @@ -6321,13 +6841,6 @@ nodemon@^2.0.19: touch "^3.1.0" undefsafe "^2.0.5" -nopt@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" - integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== - dependencies: - abbrev "1" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -6366,20 +6879,25 @@ nwsapi@^2.2.0: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + object-hash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + object-inspect@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" -object-inspect@^1.9.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== - object-keys@^1.0.11, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6397,12 +6915,28 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.8" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz#2f1fe0606ec1a7658154ccd4f728504f69667923" + integrity sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A== + dependencies: + array.prototype.reduce "^1.0.6" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + gopd "^1.0.1" + safe-array-concat "^1.1.2" object.values@^1.1.0: version "1.1.0" @@ -6502,6 +7036,11 @@ p-try@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + param-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" @@ -6567,15 +7106,19 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.5, path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -6591,6 +7134,11 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + picomatch@^2.0.4, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" @@ -6606,6 +7154,11 @@ pify@^2.3.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== +pirates@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + pirates@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" @@ -6639,6 +7192,11 @@ playwright@1.41.2: optionalDependencies: fsevents "2.3.2" +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + postcss-attribute-case-insensitive@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz#03d761b24afc04c09e757e92ff53716ae8ea2741" @@ -6804,10 +7362,10 @@ postcss-image-set-function@^4.0.7: dependencies: postcss-value-parser "^4.2.0" -postcss-import@^14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0" - integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw== +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== dependencies: postcss-value-parser "^4.0.0" read-cache "^1.0.0" @@ -6818,10 +7376,10 @@ postcss-initial@^4.0.1: resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42" integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ== -postcss-js@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" - integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== +postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== dependencies: camelcase-css "^2.0.1" @@ -6833,13 +7391,13 @@ postcss-lab-function@^4.2.1: "@csstools/postcss-progressive-custom-properties" "^1.1.0" postcss-value-parser "^4.2.0" -postcss-load-config@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855" - integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== +postcss-load-config@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== dependencies: - lilconfig "^2.0.5" - yaml "^1.10.2" + lilconfig "^3.0.0" + yaml "^2.3.4" postcss-loader@^6.2.1: version "6.2.1" @@ -6938,12 +7496,12 @@ postcss-modules-values@^4.0.0: dependencies: icss-utils "^5.0.0" -postcss-nested@5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" - integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== +postcss-nested@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" + integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== dependencies: - postcss-selector-parser "^6.0.6" + postcss-selector-parser "^6.1.1" postcss-nesting@^10.1.10: version "10.1.10" @@ -7146,7 +7704,7 @@ postcss-selector-not@^6.0.1: dependencies: postcss-selector-parser "^6.0.10" -postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: +postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: version "6.0.10" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== @@ -7154,6 +7712,14 @@ postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.4, postcss-selecto cssesc "^3.0.0" util-deprecate "^1.0.2" +postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.1.1: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-selector-parser@^6.0.2: version "6.0.4" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz#56075a1380a04604c38b063ea7767a129af5c2b3" @@ -7197,7 +7763,7 @@ postcss@^7.0.35: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.3.5, postcss@^8.4.14, postcss@^8.4.4, postcss@^8.4.7: +postcss@^8.3.5, postcss@^8.4.4, postcss@^8.4.7: version "8.4.16" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c" integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ== @@ -7206,6 +7772,15 @@ postcss@^8.3.5, postcss@^8.4.14, postcss@^8.4.4, postcss@^8.4.7: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8.4.23: + version "8.4.41" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.41.tgz#d6104d3ba272d882fe18fc07d15dc2da62fa2681" + integrity sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.1" + source-map-js "^1.2.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -7282,10 +7857,15 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== randombytes@^2.1.0: version "2.1.0" @@ -7339,12 +7919,11 @@ react-dev-utils@^12.0.1: text-table "^0.2.0" react-dom@experimental: - version "0.0.0-experimental-6ff1733e6-20230225" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-6ff1733e6-20230225.tgz#47c1e80f21230e6c650ba9e43d15fccd616441be" - integrity sha512-1vGCQDhmSOwBIb8QbTaSjBUysebPhl7WCcGuT6dW+HdlxFDvClL0M47K1e8kZWiuCkMUDjJaTlC4J32PgznbFw== + version "0.0.0-experimental-6ebfd5b0-20240818" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-6ebfd5b0-20240818.tgz#8a0b45fc4d54d45442e5194edee0114a8132bc82" + integrity sha512-G+RipTMyLYgSz4lST+8RFzP/Zdl8JaW0iWq5Yk9nG/rkdT7riWQrrMG9ZpRAxpRbBbaZ8WIgZqX5JFvRcJjyDQ== dependencies: - loose-envify "^1.1.0" - scheduler "0.0.0-experimental-6ff1733e6-20230225" + scheduler "0.0.0-experimental-6ebfd5b0-20240818" react-error-overlay@^6.0.11: version "6.0.11" @@ -7366,12 +7945,19 @@ react-refresh@^0.11.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== -react@experimental: - version "0.0.0-experimental-6ff1733e6-20230225" - resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-6ff1733e6-20230225.tgz#24bca9d60c6b3597f389e8bcd07e7b853dddc917" - integrity sha512-5syUtEwwbWzDHN84xNu9C9cciLW9sY4c19fG27EU5ApS1s+i7fFtS+KtyPMHU9S4eK0u65uQU3hWMqFvqzLHhw== +react-server-dom-webpack@experimental: + version "0.0.0-experimental-6ebfd5b0-20240818" + resolved "https://registry.yarnpkg.com/react-server-dom-webpack/-/react-server-dom-webpack-0.0.0-experimental-6ebfd5b0-20240818.tgz#56df6a7a406a033897f9bdd33b649e6e956adcef" + integrity sha512-kDPLVKaSKwDpuxGKxWS4w0VEY1O0IUJVksfA39H7nENjmFCuHybZ6rvi+hlXgJcwV3TvVeISLSmf27yvZWUriQ== dependencies: - loose-envify "^1.1.0" + acorn-loose "^8.3.0" + neo-async "^2.6.1" + webpack-sources "^3.2.3" + +react@experimental: + version "0.0.0-experimental-6ebfd5b0-20240818" + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-6ebfd5b0-20240818.tgz#80ed47abae164ace0006ef5e5931383ddb8964ae" + integrity sha512-Wkw/YNSnolRlb4q2IF738W9zDLATEDe0TLnFZJBFgb3bXLQomxChEqFG1Z2upuh0nhdnlJylCN2Q8ammQsbQLg== read-cache@^1.0.0: version "1.0.0" @@ -7388,11 +7974,11 @@ readdirp@~3.6.0: picomatch "^2.2.1" recursive-readdir@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" - integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== + version "2.2.3" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372" + integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== dependencies: - minimatch "3.0.4" + minimatch "^3.0.5" redent@^3.0.0: version "3.0.0" @@ -7402,88 +7988,65 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -regenerate-unicode-properties@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" - integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" - integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + version "10.1.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" + integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== dependencies: regenerate "^1.4.2" -regenerate-unicode-properties@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + regenerate "^1.4.2" regenerate@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.13.11: +regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.4: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regenerator-runtime@^0.13.4: - version "0.13.7" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" - integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== - -regenerator-transform@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" - integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== - dependencies: - "@babel/runtime" "^7.8.4" - -regenerator-transform@^0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" - integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== +regenerator-transform@^0.15.0, regenerator-transform@^0.15.1: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== dependencies: "@babel/runtime" "^7.8.4" regex-parser@^2.2.11: - version "2.2.11" - resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.11.tgz#3b37ec9049e19479806e878cabe7c1ca83ccfe58" - integrity sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q== + version "2.3.0" + resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.3.0.tgz#4bb61461b1a19b8b913f3960364bb57887f920ee" + integrity sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg== -regexpu-core@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" +regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.1.0" - regjsgen "^0.5.0" - regjsparser "^0.6.0" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.1.0" + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" -regexpu-core@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d" - integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== +regexpu-core@^4.6.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== dependencies: regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.0.0" -regexpu-core@^5.3.1: +regexpu-core@^5.1.0, regexpu-core@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== @@ -7495,25 +8058,15 @@ regexpu-core@^5.3.1: unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.1.0" -regjsgen@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" - -regjsgen@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" - integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== - -regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - dependencies: - jsesc "~0.5.0" +regjsgen@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== -regjsparser@^0.8.2: - version "0.8.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" - integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== dependencies: jsesc "~0.5.0" @@ -7527,7 +8080,7 @@ regjsparser@^0.9.1: relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== renderkid@^3.0.0: version "3.0.0" @@ -7543,12 +8096,18 @@ renderkid@^3.0.0: require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -7559,6 +8118,7 @@ resolve-cwd@^3.0.0: 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== resolve-from@^5.0.0: version "5.0.0" @@ -7577,42 +8137,19 @@ resolve-url-loader@^4.0.0: source-map "0.6.1" resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== - -resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.1: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^1.14.2: - version "1.19.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" - integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== - dependencies: - is-core-module "^2.1.0" - path-parse "^1.0.6" + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" + integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== -resolve@^1.19.0: - version "1.22.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== +resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.3.2: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.11.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.3.2: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - dependencies: - path-parse "^1.0.5" - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -7626,24 +8163,52 @@ rimraf@^3.0.0: glob "^7.1.3" run-parallel@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" - integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" rxjs@^7.0.0: - version "7.5.6" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" - integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" -safe-buffer@5.1.2, safe-buffer@^5.1.0, safe-buffer@~5.1.1: +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@5.1.2, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sanitize.css@*: version "13.0.0" @@ -7661,6 +8226,7 @@ sass-loader@^12.3.0: sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== saxes@^5.0.1: version "5.0.1" @@ -7669,12 +8235,10 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -scheduler@0.0.0-experimental-6ff1733e6-20230225: - version "0.0.0-experimental-6ff1733e6-20230225" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-6ff1733e6-20230225.tgz#9de04947f82afa784de799aa09aaad92ee67cb19" - integrity sha512-YDyRM4ohU6NmzsbiJ/UUdRB4ulz27n+3Su8LZ8cENrQDuu2us3sPN+y8CMGeqaNYJlS0GQTHNcLa2LZIK9BP5Q== - dependencies: - loose-envify "^1.1.0" +scheduler@0.0.0-experimental-6ebfd5b0-20240818: + version "0.0.0-experimental-6ebfd5b0-20240818" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-6ebfd5b0-20240818.tgz#583c91937f8fdde51726cf1735cdb323eb86adf2" + integrity sha512-/a4bME9pxUZOLPL8ktBU4JtqYXPk2lRslukGB93gWygXbSoNpdVfVFoSyiUlLk1bDXN0iV5NaKv3PWHOhmOn+w== schema-utils@2.7.0: version "2.7.0" @@ -7694,7 +8258,7 @@ schema-utils@^2.6.5: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== @@ -7703,17 +8267,7 @@ schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -schema-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" - integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== - dependencies: - "@types/json-schema" "^7.0.9" - ajv "^8.8.0" - ajv-formats "^2.1.1" - ajv-keywords "^5.0.0" - -schema-utils@^4.2.0: +schema-utils@^4.0.0, schema-utils@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== @@ -7728,39 +8282,49 @@ semver@7.0.0, semver@~7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@^5.3.0, semver@^5.4.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" - -semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^5.3.0, semver@^5.4.1, semver@^5.7.1: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== +semver@^7.3.2, semver@^7.3.5: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: - lru-cache "^6.0.0" + randombytes "^2.1.0" -semver@^7.3.5: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: - lru-cache "^6.0.0" + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" -serialize-javascript@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +set-function-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: - randombytes "^2.1.0" + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" setprototypeof@1.2.0: version "1.2.0" @@ -7780,40 +8344,38 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" - integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" -signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -signal-exit@^3.0.3: +signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-update-notifier@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz#7edf75c5bdd04f88828d632f762b2bc32996a9cc" - integrity sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew== + version "1.1.0" + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" + integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== dependencies: semver "~7.0.0" -sisteransi@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.3.tgz#98168d62b79e3a5e758e27ae63c4a053d748f4eb" - -sisteransi@^1.0.5: +sisteransi@^1.0.3, sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== @@ -7821,6 +8383,7 @@ sisteransi@^1.0.5: slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slash@^4.0.0: version "4.0.0" @@ -7832,28 +8395,21 @@ source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.0.1, source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== source-map-loader@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.1.tgz#9ae5edc7c2d42570934be4c95d1ccc6352eba52d" - integrity sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA== + version "3.0.2" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.2.tgz#af23192f9b344daa729f6772933194cc5fa54fee" + integrity sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg== dependencies: abab "^2.0.5" iconv-lite "^0.6.3" source-map-js "^1.0.1" -source-map-support@^0.5.6: - version "0.5.9" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@~0.5.20: +source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -7864,10 +8420,12 @@ source-map-support@~0.5.20: source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== source-map@^0.7.3: version "0.7.4" @@ -7875,22 +8433,24 @@ source-map@^0.7.3: integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== spawn-command@^0.0.2-1: - version "0.0.2-1" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg== + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" @@ -7910,9 +8470,9 @@ streamsearch@^1.1.0: integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== string-length@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" - integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" strip-ansi "^6.0.0" @@ -7925,24 +8485,7 @@ string-length@^5.0.1: char-regex "^2.0.0" strip-ansi "^7.0.1" -string-width@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^5.2.0" - -string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string-width@^4.2.3: +"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== @@ -7951,34 +8494,62 @@ string-width@^4.2.3: 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" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.3, string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + version "2.1.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.3.tgz#dee305118117d0a1843c1fc0d38d5d0754d83c60" + integrity sha512-699Ibssmj/awVzvdNk4g83/Iu8U9vDohzmA/ly2BrQWGhamuY4Tlvs5XKmKliDt3ky6SKbE1bzPhASKCFlx9Sg== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - function-bind "^1.1.1" + string.prototype.trimstart "^1.0.3" string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + version "2.1.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.3.tgz#dc16a21d7456cbc8b2c54d47fe01f06d9efe94eb" + integrity sha512-hoOq56oRFnnfDuXNy2lGHiwT77MehHv9d0zGfRZ8QdC+4zjrkFB9vd5i/zYTd/ymFBd4YxtbdgHt3U6ksGeuBw== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - function-bind "^1.1.1" - -strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - dependencies: - ansi-regex "^4.1.0" + string.prototype.trimend "^1.0.3" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +string.prototype.trimstart@^1.0.3, string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: - ansi-regex "^5.0.0" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -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== @@ -7986,9 +8557,9 @@ strip-ansi@^6.0.1: ansi-regex "^5.0.1" strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" @@ -8015,21 +8586,35 @@ strip-json-comments@^3.1.1: integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== style-loader@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" - integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== + version "3.3.4" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.4.tgz#f30f786c36db03a45cbd55b6a70d930c479090e7" + integrity sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w== stylehacks@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520" - integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q== + version "5.1.1" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" + integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw== dependencies: - browserslist "^4.16.6" + browserslist "^4.21.4" postcss-selector-parser "^6.0.4" +sucrase@^3.32.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" @@ -8048,9 +8633,9 @@ supports-color@^8.0.0, supports-color@^8.1.0: has-flag "^4.0.0" supports-hyperlinks@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" - integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" + integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" @@ -8068,6 +8653,7 @@ svg-parser@^2.0.2: svgo@^1.2.2: version "1.3.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== dependencies: chalk "^2.4.1" coa "^2.0.2" @@ -8102,36 +8688,37 @@ symbol-tree@^3.2.4: integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== tailwindcss@^3.0.2: - version "3.1.8" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.1.8.tgz#4f8520550d67a835d32f2f4021580f9fddb7b741" - integrity sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g== + version "3.4.10" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.10.tgz#70442d9aeb78758d1f911af29af8255ecdb8ffef" + integrity sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w== dependencies: + "@alloc/quick-lru" "^5.2.0" arg "^5.0.2" chokidar "^3.5.3" - color-name "^1.1.4" - detective "^5.2.1" didyoumean "^1.2.2" dlv "^1.1.3" - fast-glob "^3.2.11" + fast-glob "^3.3.0" glob-parent "^6.0.2" is-glob "^4.0.3" - lilconfig "^2.0.6" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" normalize-path "^3.0.0" object-hash "^3.0.0" picocolors "^1.0.0" - postcss "^8.4.14" - postcss-import "^14.1.0" - postcss-js "^4.0.0" - postcss-load-config "^3.1.4" - postcss-nested "5.0.6" - postcss-selector-parser "^6.0.10" - postcss-value-parser "^4.2.0" - quick-lru "^5.1.1" - resolve "^1.22.1" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" tapable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.0.tgz#0d076a172e3d9ba088fd2272b2668fb8d194b78c" + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" @@ -8146,24 +8733,24 @@ terminal-link@^2.0.0: ansi-escapes "^4.2.1" supports-hyperlinks "^2.0.0" -terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.5: - version "5.3.5" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.5.tgz#f7d82286031f915a4f8fb81af4bd35d2e3c011bc" - integrity sha512-AOEDLDxD2zylUGf/wxHxklEkOe2/r+seuyOWujejFrIxHf11brA1/dWQNIgXa1c6/Wkxgu7zvv0JhOWfc2ELEA== +terser-webpack-plugin@^5.2.5, terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== dependencies: - "@jridgewell/trace-mapping" "^0.3.14" + "@jridgewell/trace-mapping" "^0.3.20" jest-worker "^27.4.5" schema-utils "^3.1.1" - serialize-javascript "^6.0.0" - terser "^5.14.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" -terser@^5.10.0, terser@^5.14.1: - version "5.14.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" - integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== +terser@^5.10.0, terser@^5.26.0: + version "5.31.6" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.6.tgz#c63858a0f0703988d0266a82fcbf2d7ba76422b1" + integrity sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg== dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" source-map-support "~0.5.20" @@ -8179,19 +8766,36 @@ test-exclude@^6.0.0: text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + version "6.0.2" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" + integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" @@ -8206,27 +8810,19 @@ toidentifier@1.0.1: integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== touch@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" - integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== - dependencies: - nopt "~1.0.10" + version "3.1.1" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694" + integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA== tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" - universalify "^0.1.2" - -tr46@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" - integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== - dependencies: - punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" tr46@^2.1.0: version "2.1.0" @@ -8240,23 +8836,25 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -tslib@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -tslib@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" - integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^2.0.3, tslib@^2.1.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== dependencies: prelude-ls "~1.1.2" @@ -8273,6 +8871,7 @@ type-fest@^0.11.0: type-fest@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2" + integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw== type-is@~1.6.18: version "1.6.18" @@ -8282,6 +8881,50 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -8289,34 +8932,33 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + undefsafe@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== undici@^5.20.0: - version "5.20.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.20.0.tgz#6327462f5ce1d3646bcdac99da7317f455bcc263" - integrity sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g== + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== dependencies: - busboy "^1.6.0" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + "@fastify/busboy" "^2.0.0" unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - unicode-match-property-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" @@ -8325,66 +8967,48 @@ unicode-match-property-ecmascript@^2.0.0: unicode-canonical-property-names-ecmascript "^2.0.0" unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" - -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== - -unicode-match-property-value-ecmascript@^2.1.0: +unicode-match-property-value-ecmascript@^2.0.0, unicode-match-property-value-ecmascript@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== -unicode-property-aliases-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" - unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA== -universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unquote@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg== -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -update-browserslist-db@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" - integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== +update-browserslist-db@^1.0.11, update-browserslist-db@^1.0.5, update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" @@ -8393,20 +9017,33 @@ uri-js@^4.2.2, uri-js@^4.4.1: dependencies: punycode "^2.1.0" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== util.promisify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== dependencies: - define-properties "^1.1.2" - object.getownpropertydescriptors "^2.0.3" + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" utila@~0.4: version "0.4.0" resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== v8-to-istanbul@^8.1.0: version "8.1.1" @@ -8437,15 +9074,16 @@ w3c-xmlserializer@^2.0.0: xml-name-validator "^3.0.0" walker@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - makeerror "1.0.x" + makeerror "1.0.12" -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -8472,9 +9110,9 @@ webpack-dev-middleware@^5.3.4: schema-utils "^4.0.0" webpack-hot-middleware@^2.25.3: - version "2.25.3" - resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz#be343ce2848022cfd854dd82820cd730998c6794" - integrity sha512-IK/0WAHs7MTu1tzLTjio73LjS3Ov+VvBKQmE8WPlJutgG5zT6Urgq/BbAdRrHTRpyzK0dvAvFh1Qg98akxgZpA== + version "2.26.1" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.26.1.tgz#87214f1e3f9f3acab9271fef9e6ed7b637d719c0" + integrity sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A== dependencies: ansi-html-community "0.0.8" html-entities "^2.1.0" @@ -8502,55 +9140,48 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.64.4: - version "5.74.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980" - integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== + version "5.93.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" + integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== dependencies: "@types/eslint-scope" "^3.7.3" - "@types/estree" "^0.0.51" - "@webassemblyjs/ast" "1.11.1" - "@webassemblyjs/wasm-edit" "1.11.1" - "@webassemblyjs/wasm-parser" "1.11.1" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" acorn "^8.7.1" - acorn-import-assertions "^1.7.6" - browserslist "^4.14.5" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.10.0" - es-module-lexer "^0.9.0" + enhanced-resolve "^5.17.0" + es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" + graceful-fs "^4.2.11" json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.1.0" + schema-utils "^3.2.0" tapable "^2.1.1" - terser-webpack-plugin "^5.1.3" - watchpack "^2.4.0" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" webpack-sources "^3.2.3" whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^8.0.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837" - integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^2.0.2" - webidl-conversions "^6.1.0" - -whatwg-url@^8.5.0: +whatwg-url@^8.0.0, whatwg-url@^8.5.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== @@ -8559,9 +9190,32 @@ whatwg-url@^8.5.0: tr46 "^2.1.0" webidl-conversions "^6.1.0" +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" @@ -8575,8 +9229,9 @@ which@^2.0.1: wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -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== @@ -8585,9 +9240,19 @@ wrap-ansi@^7.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" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^3.0.0: version "3.0.3" @@ -8600,24 +9265,20 @@ write-file-atomic@^3.0.0: typedarray-to-buffer "^3.1.5" ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -8628,27 +9289,22 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.10.0, yaml@^1.7.2: - version "1.10.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" - integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== - -yaml@^1.10.2: +yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: version "1.10.2" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" + integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== + yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.0.0: +yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -8667,17 +9323,17 @@ yargs@^16.2.0: yargs-parser "^20.2.2" yargs@^17.3.1: - version "17.5.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" - integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: - cliui "^7.0.2" + cliui "^8.0.1" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^21.0.0" + yargs-parser "^21.1.1" yocto-queue@^0.1.0: version "0.1.0" diff --git a/packages/react-server-dom-webpack/package.json b/packages/react-server-dom-webpack/package.json index 7a1fe29d4d4a9..f0c33a7441162 100644 --- a/packages/react-server-dom-webpack/package.json +++ b/packages/react-server-dom-webpack/package.json @@ -106,6 +106,7 @@ }, "dependencies": { "acorn-loose": "^8.3.0", - "neo-async": "^2.6.1" + "neo-async": "^2.6.1", + "webpack-sources": "^3.2.0" } } diff --git a/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeLoader.js b/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeLoader.js index 5dab530965bc9..9799acc3a07b2 100644 --- a/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeLoader.js +++ b/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeLoader.js @@ -9,6 +9,9 @@ import * as acorn from 'acorn-loose'; +import readMappings from 'webpack-sources/lib/helpers/readMappings.js'; +import createMappingsSerializer from 'webpack-sources/lib/helpers/createMappingsSerializer.js'; + type ResolveContext = { conditions: Array, parentURL: string | void, @@ -95,45 +98,102 @@ export async function getSource( return defaultGetSource(url, context, defaultGetSource); } -function addLocalExportedNames(names: Map, node: any) { +type ExportedEntry = { + localName: string, + exportedName: string, + type: null | string, + loc: { + start: {line: number, column: number}, + end: {line: number, column: number}, + }, + originalLine: number, + originalColumn: number, + originalSource: number, + nameIndex: number, +}; + +function addExportedEntry( + exportedEntries: Array, + localNames: Set, + localName: string, + exportedName: string, + type: null | 'function', + loc: { + start: {line: number, column: number}, + end: {line: number, column: number}, + }, +) { + if (localNames.has(localName)) { + // If the same local name is exported more than once, we only need one of the names. + return; + } + exportedEntries.push({ + localName, + exportedName, + type, + loc, + originalLine: -1, + originalColumn: -1, + originalSource: -1, + nameIndex: -1, + }); +} + +function addLocalExportedNames( + exportedEntries: Array, + localNames: Set, + node: any, +) { switch (node.type) { case 'Identifier': - names.set(node.name, node.name); + addExportedEntry( + exportedEntries, + localNames, + node.name, + node.name, + null, + node.loc, + ); return; case 'ObjectPattern': for (let i = 0; i < node.properties.length; i++) - addLocalExportedNames(names, node.properties[i]); + addLocalExportedNames(exportedEntries, localNames, node.properties[i]); return; case 'ArrayPattern': for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; - if (element) addLocalExportedNames(names, element); + if (element) + addLocalExportedNames(exportedEntries, localNames, element); } return; case 'Property': - addLocalExportedNames(names, node.value); + addLocalExportedNames(exportedEntries, localNames, node.value); return; case 'AssignmentPattern': - addLocalExportedNames(names, node.left); + addLocalExportedNames(exportedEntries, localNames, node.left); return; case 'RestElement': - addLocalExportedNames(names, node.argument); + addLocalExportedNames(exportedEntries, localNames, node.argument); return; case 'ParenthesizedExpression': - addLocalExportedNames(names, node.expression); + addLocalExportedNames(exportedEntries, localNames, node.expression); return; } } function transformServerModule( source: string, - body: any, + program: any, url: string, + sourceMap: any, loader: LoadFunction, ): string { - // If the same local name is exported more than once, we only need one of the names. - const localNames: Map = new Map(); - const localTypes: Map = new Map(); + const body = program.body; + + // This entry list needs to be in source location order. + const exportedEntries: Array = []; + // Dedupe set. + const localNames: Set = new Set(); for (let i = 0; i < body.length; i++) { const node = body[i]; @@ -143,11 +203,24 @@ function transformServerModule( break; case 'ExportDefaultDeclaration': if (node.declaration.type === 'Identifier') { - localNames.set(node.declaration.name, 'default'); + addExportedEntry( + exportedEntries, + localNames, + node.declaration.name, + 'default', + null, + node.declaration.loc, + ); } else if (node.declaration.type === 'FunctionDeclaration') { if (node.declaration.id) { - localNames.set(node.declaration.id.name, 'default'); - localTypes.set(node.declaration.id.name, 'function'); + addExportedEntry( + exportedEntries, + localNames, + node.declaration.id.name, + 'default', + 'function', + node.declaration.id.loc, + ); } else { // TODO: This needs to be rewritten inline because it doesn't have a local name. } @@ -158,41 +231,230 @@ function transformServerModule( if (node.declaration.type === 'VariableDeclaration') { const declarations = node.declaration.declarations; for (let j = 0; j < declarations.length; j++) { - addLocalExportedNames(localNames, declarations[j].id); + addLocalExportedNames( + exportedEntries, + localNames, + declarations[j].id, + ); } } else { const name = node.declaration.id.name; - localNames.set(name, name); - if (node.declaration.type === 'FunctionDeclaration') { - localTypes.set(name, 'function'); - } + addExportedEntry( + exportedEntries, + localNames, + name, + name, + + node.declaration.type === 'FunctionDeclaration' + ? 'function' + : null, + node.declaration.id.loc, + ); } } if (node.specifiers) { const specifiers = node.specifiers; for (let j = 0; j < specifiers.length; j++) { const specifier = specifiers[j]; - localNames.set(specifier.local.name, specifier.exported.name); + addExportedEntry( + exportedEntries, + localNames, + specifier.local.name, + specifier.exported.name, + null, + specifier.local.loc, + ); } } continue; } } - if (localNames.size === 0) { - return source; - } - let newSrc = source + '\n\n;'; - newSrc += - 'import {registerServerReference} from "react-server-dom-webpack/server";\n'; - localNames.forEach(function (exported, local) { - if (localTypes.get(local) !== 'function') { - // We first check if the export is a function and if so annotate it. - newSrc += 'if (typeof ' + local + ' === "function") '; + + let mappings = + sourceMap && typeof sourceMap.mappings === 'string' + ? sourceMap.mappings + : ''; + let newSrc = source; + + if (exportedEntries.length > 0) { + let lastSourceIndex = 0; + let lastOriginalLine = 0; + let lastOriginalColumn = 0; + let lastNameIndex = 0; + let sourceLineCount = 0; + let lastMappedLine = 0; + + if (sourceMap) { + // We iterate source mapping entries and our matched exports in parallel to source map + // them to their original location. + let nextEntryIdx = 0; + let nextEntryLine = exportedEntries[nextEntryIdx].loc.start.line; + let nextEntryColumn = exportedEntries[nextEntryIdx].loc.start.column; + readMappings( + mappings, + ( + generatedLine: number, + generatedColumn: number, + sourceIndex: number, + originalLine: number, + originalColumn: number, + nameIndex: number, + ) => { + if ( + generatedLine > nextEntryLine || + (generatedLine === nextEntryLine && + generatedColumn > nextEntryColumn) + ) { + // We're past the entry which means that the best match we have is the previous entry. + if (lastMappedLine === nextEntryLine) { + // Match + exportedEntries[nextEntryIdx].originalLine = lastOriginalLine; + exportedEntries[nextEntryIdx].originalColumn = lastOriginalColumn; + exportedEntries[nextEntryIdx].originalSource = lastSourceIndex; + exportedEntries[nextEntryIdx].nameIndex = lastNameIndex; + } else { + // Skip if we didn't have any mappings on the exported line. + } + nextEntryIdx++; + if (nextEntryIdx < exportedEntries.length) { + nextEntryLine = exportedEntries[nextEntryIdx].loc.start.line; + nextEntryColumn = exportedEntries[nextEntryIdx].loc.start.column; + } else { + nextEntryLine = -1; + nextEntryColumn = -1; + } + } + lastMappedLine = generatedLine; + if (sourceIndex > -1) { + lastSourceIndex = sourceIndex; + } + if (originalLine > -1) { + lastOriginalLine = originalLine; + } + if (originalColumn > -1) { + lastOriginalColumn = originalColumn; + } + if (nameIndex > -1) { + lastNameIndex = nameIndex; + } + }, + ); + if (nextEntryIdx < exportedEntries.length) { + if (lastMappedLine === nextEntryLine) { + // Match + exportedEntries[nextEntryIdx].originalLine = lastOriginalLine; + exportedEntries[nextEntryIdx].originalColumn = lastOriginalColumn; + exportedEntries[nextEntryIdx].originalSource = lastSourceIndex; + exportedEntries[nextEntryIdx].nameIndex = lastNameIndex; + } + } + + for ( + let lastIdx = mappings.length - 1; + lastIdx >= 0 && mappings[lastIdx] === ';'; + lastIdx-- + ) { + // If the last mapped lines don't contain any segments, we don't get a callback from readMappings + // so we need to pad the number of mapped lines, with one for each empty line. + lastMappedLine++; + } + + sourceLineCount = program.loc.end.line; + if (sourceLineCount < lastMappedLine) { + throw new Error( + 'The source map has more mappings than there are lines.', + ); + } + // If the original source string had more lines than there are mappings in the source map. + // Add some extra padding of unmapped lines so that any lines that we add line up. + for ( + let extraLines = sourceLineCount - lastMappedLine; + extraLines > 0; + extraLines-- + ) { + mappings += ';'; + } + } else { + // If a file doesn't have a source map then we generate a blank source map that just + // contains the original content and segments pointing to the original lines. + sourceLineCount = 1; + let idx = -1; + while ((idx = source.indexOf('\n', idx + 1)) !== -1) { + sourceLineCount++; + } + mappings = 'AAAA' + ';AACA'.repeat(sourceLineCount - 1); + sourceMap = { + version: 3, + sources: [url], + sourcesContent: [source], + mappings: mappings, + sourceRoot: '', + }; + lastSourceIndex = 0; + lastOriginalLine = sourceLineCount; + lastOriginalColumn = 0; + lastNameIndex = -1; + lastMappedLine = sourceLineCount; + + for (let i = 0; i < exportedEntries.length; i++) { + // Point each entry to original location. + const entry = exportedEntries[i]; + entry.originalSource = 0; + entry.originalLine = entry.loc.start.line; + // We use column zero since we do the short-hand line-only source maps above. + entry.originalColumn = 0; // entry.loc.start.column; + } } - newSrc += 'registerServerReference(' + local + ','; - newSrc += JSON.stringify(url) + ','; - newSrc += JSON.stringify(exported) + ');\n'; - }); + + newSrc += '\n\n;'; + newSrc += + 'import {registerServerReference} from "react-server-dom-webpack/server";\n'; + if (mappings) { + mappings += ';;'; + } + + const createMapping = createMappingsSerializer(); + + // Create an empty mapping pointing to where we last left off to reset the counters. + let generatedLine = 1; + createMapping( + generatedLine, + 0, + lastSourceIndex, + lastOriginalLine, + lastOriginalColumn, + lastNameIndex, + ); + for (let i = 0; i < exportedEntries.length; i++) { + const entry = exportedEntries[i]; + generatedLine++; + if (entry.type !== 'function') { + // We first check if the export is a function and if so annotate it. + newSrc += 'if (typeof ' + entry.localName + ' === "function") '; + } + newSrc += 'registerServerReference(' + entry.localName + ','; + newSrc += JSON.stringify(url) + ','; + newSrc += JSON.stringify(entry.exportedName) + ');\n'; + + mappings += createMapping( + generatedLine, + 0, + entry.originalSource, + entry.originalLine, + entry.originalColumn, + entry.nameIndex, + ); + } + } + + if (sourceMap) { + // Override with an new mappings and serialize an inline source map. + sourceMap.mappings = mappings; + newSrc += + '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' + + Buffer.from(JSON.stringify(sourceMap)).toString('base64'); + } + return newSrc; } @@ -307,10 +569,13 @@ async function parseExportNamesInto( } async function transformClientModule( - body: any, + program: any, url: string, + sourceMap: any, loader: LoadFunction, ): Promise { + const body = program.body; + const names: Array = []; await parseExportNamesInto(body, names, url, loader); @@ -351,6 +616,9 @@ async function transformClientModule( newSrc += JSON.stringify(url) + ','; newSrc += JSON.stringify(name) + ');\n'; } + + // TODO: Generate source maps for Client Reference functions so they can point to their + // original locations. return newSrc; } @@ -391,12 +659,36 @@ async function transformModuleIfNeeded( return source; } - let body; + let sourceMappingURL = null; + let sourceMappingStart = 0; + let sourceMappingEnd = 0; + let sourceMappingLines = 0; + + let program; try { - body = acorn.parse(source, { + program = acorn.parse(source, { ecmaVersion: '2024', sourceType: 'module', - }).body; + locations: true, + onComment( + block: boolean, + text: string, + start: number, + end: number, + startLoc: {line: number, column: number}, + endLoc: {line: number, column: number}, + ) { + if ( + text.startsWith('# sourceMappingURL=') || + text.startsWith('@ sourceMappingURL=') + ) { + sourceMappingURL = text.slice(19); + sourceMappingStart = start; + sourceMappingEnd = end; + sourceMappingLines = endLoc.line - startLoc.line; + } + }, + }); } catch (x) { // eslint-disable-next-line react-internal/no-production-logging console.error('Error parsing %s %s', url, x.message); @@ -405,6 +697,8 @@ async function transformModuleIfNeeded( let useClient = false; let useServer = false; + + const body = program.body; for (let i = 0; i < body.length; i++) { const node = body[i]; if (node.type !== 'ExpressionStatement' || !node.directive) { @@ -428,11 +722,38 @@ async function transformModuleIfNeeded( ); } + let sourceMap = null; + if (sourceMappingURL) { + const sourceMapResult = await loader( + sourceMappingURL, + // $FlowFixMe + { + format: 'json', + conditions: [], + importAssertions: {type: 'json'}, + importAttributes: {type: 'json'}, + }, + loader, + ); + const sourceMapString = + typeof sourceMapResult.source === 'string' + ? sourceMapResult.source + : // $FlowFixMe + sourceMapResult.source.toString('utf8'); + sourceMap = JSON.parse(sourceMapString); + + // Strip the source mapping comment. We'll re-add it below if needed. + source = + source.slice(0, sourceMappingStart) + + '\n'.repeat(sourceMappingLines) + + source.slice(sourceMappingEnd); + } + if (useClient) { - return transformClientModule(body, url, loader); + return transformClientModule(program, url, sourceMap, loader); } - return transformServerModule(source, body, url, loader); + return transformServerModule(source, program, url, sourceMap, loader); } export async function transformSource( diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index e1ebc1c945a0d..2afa0cc98b100 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -22,6 +22,9 @@ const importSideEffects = Object.freeze({ 'react-dom': HAS_NO_SIDE_EFFECTS_ON_IMPORT, url: HAS_NO_SIDE_EFFECTS_ON_IMPORT, ReactNativeInternalFeatureFlags: HAS_NO_SIDE_EFFECTS_ON_IMPORT, + 'webpack-sources/lib/helpers/createMappingsSerializer.js': + HAS_NO_SIDE_EFFECTS_ON_IMPORT, + 'webpack-sources/lib/helpers/readMappings.js': HAS_NO_SIDE_EFFECTS_ON_IMPORT, }); // Bundles exporting globals that other modules rely on. diff --git a/yarn.lock b/yarn.lock index 3ecf3e738e190..473020cfa1fd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11347,11 +11347,6 @@ lodash.omitby@4.6.0: resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791" integrity sha1-XBX/R1StVVAWtTwEExHo8HkgR5E= -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= - lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -11603,11 +11598,6 @@ memfs@^3.4.3: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -memoize-one@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-3.1.1.tgz#ef609811e3bc28970eac2884eece64d167830d17" - integrity sha512-YqVh744GsMlZu6xkhGslPSqSurOv6P+kLN2J3ysBZfagLcL5FdRK/0UpgLoL8hwjjEvvAVkjJZyFP+1T6p1vgA== - memoize-one@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" @@ -16499,7 +16489,7 @@ webpack-merge@^5.7.3: clone-deep "^4.0.1" wildcard "^2.0.0" -webpack-sources@^3.2.3: +webpack-sources@^3.2.0, webpack-sources@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== From 1228a28398bbf7b4d15cd148496853342e63c041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 21 Aug 2024 09:58:31 -0400 Subject: [PATCH 031/426] Remove turbopack unbundled/register/loader (#30756) The unbundled form is just a way to show case a prototype for how an unbundled version of RSC can work. It's not really intended for every bundler combination to provide such a configuration. There's no configuration of Turbopack that supports this mode atm and possibly never will be since it's more of an integrated server/client experience. This removes the unbundled form and node register/loaders from the turbopack build. --- ...ClientConfig.dom-node-turbopack-bundled.js | 16 - ...ctFlightClientConfig.dom-node-turbopack.js | 3 +- .../client.node.unbundled.js | 10 - .../esm/package.json | 3 - ...er-dom-turbopack-node-loader.production.js | 10 - .../node-register.js | 10 - .../npm/client.node.unbundled.js | 7 - .../npm/esm/package.json | 3 - .../npm/node-register.js | 3 - .../npm/server.node.unbundled.js | 18 - .../npm/static.node.unbundled.js | 12 - .../react-server-dom-turbopack/package.json | 30 +- .../server.node.unbundled.js | 20 - .../src/ReactFlightTurbopackNodeLoader.js | 483 ------------------ .../src/ReactFlightTurbopackNodeRegister.js | 109 ---- .../__tests__/ReactFlightTurbopackDOM-test.js | 4 +- .../ReactFlightTurbopackDOMBrowser-test.js | 2 +- .../ReactFlightTurbopackDOMEdge-test.js | 2 +- .../ReactFlightTurbopackDOMForm-test.js | 147 ------ .../ReactFlightTurbopackDOMNode-test.js | 2 +- .../ReactFlightTurbopackDOMReply-test.js | 2 +- .../ReactFlightTurbopackDOMReplyEdge-test.js | 2 +- .../src/__tests__/utils/TurbopackMock.js | 62 +-- .../react-flight-dom-server.node.unbundled.js | 21 - ...flight-dom-server.node.unbundled.stable.js | 20 - .../static.node.unbundled.js | 10 - scripts/rollup/bundles.js | 50 -- scripts/shared/inlinedHostConfigs.js | 43 -- 28 files changed, 38 insertions(+), 1066 deletions(-) delete mode 100644 packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack-bundled.js delete mode 100644 packages/react-server-dom-turbopack/client.node.unbundled.js delete mode 100644 packages/react-server-dom-turbopack/esm/package.json delete mode 100644 packages/react-server-dom-turbopack/esm/react-server-dom-turbopack-node-loader.production.js delete mode 100644 packages/react-server-dom-turbopack/node-register.js delete mode 100644 packages/react-server-dom-turbopack/npm/client.node.unbundled.js delete mode 100644 packages/react-server-dom-turbopack/npm/esm/package.json delete mode 100644 packages/react-server-dom-turbopack/npm/node-register.js delete mode 100644 packages/react-server-dom-turbopack/npm/server.node.unbundled.js delete mode 100644 packages/react-server-dom-turbopack/npm/static.node.unbundled.js delete mode 100644 packages/react-server-dom-turbopack/server.node.unbundled.js delete mode 100644 packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeLoader.js delete mode 100644 packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeRegister.js delete mode 100644 packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMForm-test.js delete mode 100644 packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.js delete mode 100644 packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.stable.js delete mode 100644 packages/react-server-dom-turbopack/static.node.unbundled.js diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack-bundled.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack-bundled.js deleted file mode 100644 index f4226a93d86bc..0000000000000 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack-bundled.js +++ /dev/null @@ -1,16 +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. - * - * @flow - */ - -export * from 'react-client/src/ReactFlightClientStreamConfigNode'; -export * from 'react-client/src/ReactClientConsoleConfigServer'; -export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack'; -export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopackServer'; -export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigTargetTurbopackServer'; -export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; -export const usedWithSSR = true; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js index b6f2b77dd3686..f4226a93d86bc 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-node-turbopack.js @@ -9,7 +9,8 @@ export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactClientConsoleConfigServer'; -export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode'; +export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack'; +export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopackServer'; export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigTargetTurbopackServer'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export const usedWithSSR = true; diff --git a/packages/react-server-dom-turbopack/client.node.unbundled.js b/packages/react-server-dom-turbopack/client.node.unbundled.js deleted file mode 100644 index c2e364f42f133..0000000000000 --- a/packages/react-server-dom-turbopack/client.node.unbundled.js +++ /dev/null @@ -1,10 +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. - * - * @flow - */ - -export * from './src/client/ReactFlightDOMClientNode'; diff --git a/packages/react-server-dom-turbopack/esm/package.json b/packages/react-server-dom-turbopack/esm/package.json deleted file mode 100644 index 3dbc1ca591c05..0000000000000 --- a/packages/react-server-dom-turbopack/esm/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/packages/react-server-dom-turbopack/esm/react-server-dom-turbopack-node-loader.production.js b/packages/react-server-dom-turbopack/esm/react-server-dom-turbopack-node-loader.production.js deleted file mode 100644 index ef6486656cafe..0000000000000 --- a/packages/react-server-dom-turbopack/esm/react-server-dom-turbopack-node-loader.production.js +++ /dev/null @@ -1,10 +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. - * - * @flow - */ - -export * from '../src/ReactFlightTurbopackNodeLoader.js'; diff --git a/packages/react-server-dom-turbopack/node-register.js b/packages/react-server-dom-turbopack/node-register.js deleted file mode 100644 index 0d399f3842731..0000000000000 --- a/packages/react-server-dom-turbopack/node-register.js +++ /dev/null @@ -1,10 +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. - * - * @flow - */ - -module.exports = require('./src/ReactFlightTurbopackNodeRegister'); diff --git a/packages/react-server-dom-turbopack/npm/client.node.unbundled.js b/packages/react-server-dom-turbopack/npm/client.node.unbundled.js deleted file mode 100644 index 04eb5b1972bed..0000000000000 --- a/packages/react-server-dom-turbopack/npm/client.node.unbundled.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -if (process.env.NODE_ENV === 'production') { - module.exports = require('./cjs/react-server-dom-turbopack-client.node.unbundled.production.js'); -} else { - module.exports = require('./cjs/react-server-dom-turbopack-client.node.unbundled.development.js'); -} diff --git a/packages/react-server-dom-turbopack/npm/esm/package.json b/packages/react-server-dom-turbopack/npm/esm/package.json deleted file mode 100644 index 3dbc1ca591c05..0000000000000 --- a/packages/react-server-dom-turbopack/npm/esm/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/packages/react-server-dom-turbopack/npm/node-register.js b/packages/react-server-dom-turbopack/npm/node-register.js deleted file mode 100644 index 7506743f033fa..0000000000000 --- a/packages/react-server-dom-turbopack/npm/node-register.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -module.exports = require('./cjs/react-server-dom-turbopack-node-register.js'); diff --git a/packages/react-server-dom-turbopack/npm/server.node.unbundled.js b/packages/react-server-dom-turbopack/npm/server.node.unbundled.js deleted file mode 100644 index 1e8648ccef133..0000000000000 --- a/packages/react-server-dom-turbopack/npm/server.node.unbundled.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - -var s; -if (process.env.NODE_ENV === 'production') { - s = require('./cjs/react-server-dom-turbopack-server.node.unbundled.production.js'); -} else { - s = require('./cjs/react-server-dom-turbopack-server.node.unbundled.development.js'); -} - -exports.renderToPipeableStream = s.renderToPipeableStream; -exports.decodeReplyFromBusboy = s.decodeReplyFromBusboy; -exports.decodeReply = s.decodeReply; -exports.decodeAction = s.decodeAction; -exports.decodeFormState = s.decodeFormState; -exports.registerServerReference = s.registerServerReference; -exports.registerClientReference = s.registerClientReference; -exports.createClientModuleProxy = s.createClientModuleProxy; -exports.createTemporaryReferenceSet = s.createTemporaryReferenceSet; diff --git a/packages/react-server-dom-turbopack/npm/static.node.unbundled.js b/packages/react-server-dom-turbopack/npm/static.node.unbundled.js deleted file mode 100644 index e77863bf36a60..0000000000000 --- a/packages/react-server-dom-turbopack/npm/static.node.unbundled.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -var s; -if (process.env.NODE_ENV === 'production') { - s = require('./cjs/react-server-dom-turbopack-server.node.unbundled.production.js'); -} else { - s = require('./cjs/react-server-dom-turbopack-server.node.unbundled.development.js'); -} - -if (s.prerenderToNodeStream) { - exports.prerenderToNodeStream = s.prerenderToNodeStream; -} diff --git a/packages/react-server-dom-turbopack/package.json b/packages/react-server-dom-turbopack/package.json index 93cd7d37a04ae..3b638137612da 100644 --- a/packages/react-server-dom-turbopack/package.json +++ b/packages/react-server-dom-turbopack/package.json @@ -16,20 +16,15 @@ "client.browser.js", "client.edge.js", "client.node.js", - "client.node.unbundled.js", "server.js", "server.browser.js", "server.edge.js", "server.node.js", - "server.node.unbundled.js", "static.js", "static.browser.js", "static.edge.js", "static.node.js", - "static.node.unbundled.js", - "node-register.js", - "cjs/", - "esm/" + "cjs/" ], "exports": { ".": "./index.js", @@ -37,11 +32,7 @@ "workerd": "./client.edge.js", "deno": "./client.edge.js", "worker": "./client.edge.js", - "node": { - "turbopack": "./client.node.js", - "webpack": "./client.node.js", - "default": "./client.node.unbundled.js" - }, + "node": "./client.node.js", "edge-light": "./client.edge.js", "browser": "./client.browser.js", "default": "./client.browser.js" @@ -49,16 +40,11 @@ "./client.browser": "./client.browser.js", "./client.edge": "./client.edge.js", "./client.node": "./client.node.js", - "./client.node.unbundled": "./client.node.unbundled.js", "./server": { "react-server": { "workerd": "./server.edge.js", "deno": "./server.browser.js", - "node": { - "turbopack": "./server.node.js", - "webpack": "./server.node.js", - "default": "./server.node.unbundled.js" - }, + "node": "./server.node.js", "edge-light": "./server.edge.js", "browser": "./server.browser.js" }, @@ -67,16 +53,11 @@ "./server.browser": "./server.browser.js", "./server.edge": "./server.edge.js", "./server.node": "./server.node.js", - "./server.node.unbundled": "./server.node.unbundled.js", "./static": { "react-server": { "workerd": "./static.edge.js", "deno": "./static.browser.js", - "node": { - "turbopack": "./static.node.js", - "webpack": "./static.node.js", - "default": "./static.node.unbundled.js" - }, + "node": "./static.node.js", "edge-light": "./static.edge.js", "browser": "./static.browser.js" }, @@ -85,9 +66,6 @@ "./static.browser": "./static.browser.js", "./static.edge": "./static.edge.js", "./static.node": "./static.node.js", - "./static.node.unbundled": "./static.node.unbundled.js", - "./node-loader": "./esm/react-server-dom-turbopack-node-loader.production.js", - "./node-register": "./node-register.js", "./src/*": "./src/*.js", "./package.json": "./package.json" }, diff --git a/packages/react-server-dom-turbopack/server.node.unbundled.js b/packages/react-server-dom-turbopack/server.node.unbundled.js deleted file mode 100644 index 9b8455bf66877..0000000000000 --- a/packages/react-server-dom-turbopack/server.node.unbundled.js +++ /dev/null @@ -1,20 +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. - * - * @flow - */ - -export { - renderToPipeableStream, - decodeReplyFromBusboy, - decodeReply, - decodeAction, - decodeFormState, - registerServerReference, - registerClientReference, - createClientModuleProxy, - createTemporaryReferenceSet, -} from './src/server/react-flight-dom-server.node.unbundled'; diff --git a/packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeLoader.js b/packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeLoader.js deleted file mode 100644 index b2f80e6b915f7..0000000000000 --- a/packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeLoader.js +++ /dev/null @@ -1,483 +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. - * - * @flow - */ - -import * as acorn from 'acorn-loose'; - -type ResolveContext = { - conditions: Array, - parentURL: string | void, -}; - -type ResolveFunction = ( - string, - ResolveContext, - ResolveFunction, -) => {url: string} | Promise<{url: string}>; - -type GetSourceContext = { - format: string, -}; - -type GetSourceFunction = ( - string, - GetSourceContext, - GetSourceFunction, -) => Promise<{source: Source}>; - -type TransformSourceContext = { - format: string, - url: string, -}; - -type TransformSourceFunction = ( - Source, - TransformSourceContext, - TransformSourceFunction, -) => Promise<{source: Source}>; - -type LoadContext = { - conditions: Array, - format: string | null | void, - importAssertions: Object, -}; - -type LoadFunction = ( - string, - LoadContext, - LoadFunction, -) => Promise<{format: string, shortCircuit?: boolean, source: Source}>; - -type Source = string | ArrayBuffer | Uint8Array; - -let warnedAboutConditionsFlag = false; - -let stashedGetSource: null | GetSourceFunction = null; -let stashedResolve: null | ResolveFunction = null; - -export async function resolve( - specifier: string, - context: ResolveContext, - defaultResolve: ResolveFunction, -): Promise<{url: string}> { - // We stash this in case we end up needing to resolve export * statements later. - stashedResolve = defaultResolve; - - if (!context.conditions.includes('react-server')) { - context = { - ...context, - conditions: [...context.conditions, 'react-server'], - }; - if (!warnedAboutConditionsFlag) { - warnedAboutConditionsFlag = true; - // eslint-disable-next-line react-internal/no-production-logging - console.warn( - 'You did not run Node.js with the `--conditions react-server` flag. ' + - 'Any "react-server" override will only work with ESM imports.', - ); - } - } - return await defaultResolve(specifier, context, defaultResolve); -} - -export async function getSource( - url: string, - context: GetSourceContext, - defaultGetSource: GetSourceFunction, -): Promise<{source: Source}> { - // We stash this in case we end up needing to resolve export * statements later. - stashedGetSource = defaultGetSource; - return defaultGetSource(url, context, defaultGetSource); -} - -function addLocalExportedNames(names: Map, node: any) { - switch (node.type) { - case 'Identifier': - names.set(node.name, node.name); - return; - case 'ObjectPattern': - for (let i = 0; i < node.properties.length; i++) - addLocalExportedNames(names, node.properties[i]); - return; - case 'ArrayPattern': - for (let i = 0; i < node.elements.length; i++) { - const element = node.elements[i]; - if (element) addLocalExportedNames(names, element); - } - return; - case 'Property': - addLocalExportedNames(names, node.value); - return; - case 'AssignmentPattern': - addLocalExportedNames(names, node.left); - return; - case 'RestElement': - addLocalExportedNames(names, node.argument); - return; - case 'ParenthesizedExpression': - addLocalExportedNames(names, node.expression); - return; - } -} - -function transformServerModule( - source: string, - body: any, - url: string, - loader: LoadFunction, -): string { - // If the same local name is exported more than once, we only need one of the names. - const localNames: Map = new Map(); - const localTypes: Map = new Map(); - - for (let i = 0; i < body.length; i++) { - const node = body[i]; - switch (node.type) { - case 'ExportAllDeclaration': - // If export * is used, the other file needs to explicitly opt into "use server" too. - break; - case 'ExportDefaultDeclaration': - if (node.declaration.type === 'Identifier') { - localNames.set(node.declaration.name, 'default'); - } else if (node.declaration.type === 'FunctionDeclaration') { - if (node.declaration.id) { - localNames.set(node.declaration.id.name, 'default'); - localTypes.set(node.declaration.id.name, 'function'); - } else { - // TODO: This needs to be rewritten inline because it doesn't have a local name. - } - } - continue; - case 'ExportNamedDeclaration': - if (node.declaration) { - if (node.declaration.type === 'VariableDeclaration') { - const declarations = node.declaration.declarations; - for (let j = 0; j < declarations.length; j++) { - addLocalExportedNames(localNames, declarations[j].id); - } - } else { - const name = node.declaration.id.name; - localNames.set(name, name); - if (node.declaration.type === 'FunctionDeclaration') { - localTypes.set(name, 'function'); - } - } - } - if (node.specifiers) { - const specifiers = node.specifiers; - for (let j = 0; j < specifiers.length; j++) { - const specifier = specifiers[j]; - localNames.set(specifier.local.name, specifier.exported.name); - } - } - continue; - } - } - if (localNames.size === 0) { - return source; - } - let newSrc = source + '\n\n;'; - newSrc += - 'import {registerServerReference} from "react-server-dom-turbopack/server";\n'; - localNames.forEach(function (exported, local) { - if (localTypes.get(local) !== 'function') { - // We first check if the export is a function and if so annotate it. - newSrc += 'if (typeof ' + local + ' === "function") '; - } - newSrc += 'registerServerReference(' + local + ','; - newSrc += JSON.stringify(url) + ','; - newSrc += JSON.stringify(exported) + ');\n'; - }); - return newSrc; -} - -function addExportNames(names: Array, node: any) { - switch (node.type) { - case 'Identifier': - names.push(node.name); - return; - case 'ObjectPattern': - for (let i = 0; i < node.properties.length; i++) - addExportNames(names, node.properties[i]); - return; - case 'ArrayPattern': - for (let i = 0; i < node.elements.length; i++) { - const element = node.elements[i]; - if (element) addExportNames(names, element); - } - return; - case 'Property': - addExportNames(names, node.value); - return; - case 'AssignmentPattern': - addExportNames(names, node.left); - return; - case 'RestElement': - addExportNames(names, node.argument); - return; - case 'ParenthesizedExpression': - addExportNames(names, node.expression); - return; - } -} - -function resolveClientImport( - specifier: string, - parentURL: string, -): {url: string} | Promise<{url: string}> { - // Resolve an import specifier as if it was loaded by the client. This doesn't use - // the overrides that this loader does but instead reverts to the default. - // This resolution algorithm will not necessarily have the same configuration - // as the actual client loader. It should mostly work and if it doesn't you can - // always convert to explicit exported names instead. - const conditions = ['node', 'import']; - if (stashedResolve === null) { - throw new Error( - 'Expected resolve to have been called before transformSource', - ); - } - return stashedResolve(specifier, {conditions, parentURL}, stashedResolve); -} - -async function parseExportNamesInto( - body: any, - names: Array, - parentURL: string, - loader: LoadFunction, -): Promise { - for (let i = 0; i < body.length; i++) { - const node = body[i]; - switch (node.type) { - case 'ExportAllDeclaration': - if (node.exported) { - addExportNames(names, node.exported); - continue; - } else { - const {url} = await resolveClientImport(node.source.value, parentURL); - const {source} = await loader( - url, - {format: 'module', conditions: [], importAssertions: {}}, - loader, - ); - if (typeof source !== 'string') { - throw new Error('Expected the transformed source to be a string.'); - } - let childBody; - try { - childBody = acorn.parse(source, { - ecmaVersion: '2024', - sourceType: 'module', - }).body; - } catch (x) { - // eslint-disable-next-line react-internal/no-production-logging - console.error('Error parsing %s %s', url, x.message); - continue; - } - await parseExportNamesInto(childBody, names, url, loader); - continue; - } - case 'ExportDefaultDeclaration': - names.push('default'); - continue; - case 'ExportNamedDeclaration': - if (node.declaration) { - if (node.declaration.type === 'VariableDeclaration') { - const declarations = node.declaration.declarations; - for (let j = 0; j < declarations.length; j++) { - addExportNames(names, declarations[j].id); - } - } else { - addExportNames(names, node.declaration.id); - } - } - if (node.specifiers) { - const specifiers = node.specifiers; - for (let j = 0; j < specifiers.length; j++) { - addExportNames(names, specifiers[j].exported); - } - } - continue; - } - } -} - -async function transformClientModule( - body: any, - url: string, - loader: LoadFunction, -): Promise { - const names: Array = []; - - await parseExportNamesInto(body, names, url, loader); - - if (names.length === 0) { - return ''; - } - - let newSrc = - 'import {registerClientReference} from "react-server-dom-turbopack/server";\n'; - for (let i = 0; i < names.length; i++) { - const name = names[i]; - if (name === 'default') { - newSrc += 'export default '; - newSrc += 'registerClientReference(function() {'; - newSrc += - 'throw new Error(' + - JSON.stringify( - `Attempted to call the default export of ${url} from the server ` + - `but it's on the client. It's not possible to invoke a client function from ` + - `the server, it can only be rendered as a Component or passed to props of a ` + - `Client Component.`, - ) + - ');'; - } else { - newSrc += 'export const ' + name + ' = '; - newSrc += 'registerClientReference(function() {'; - newSrc += - 'throw new Error(' + - JSON.stringify( - `Attempted to call ${name}() from the server but ${name} is on the client. ` + - `It's not possible to invoke a client function from the server, it can ` + - `only be rendered as a Component or passed to props of a Client Component.`, - ) + - ');'; - } - newSrc += '},'; - newSrc += JSON.stringify(url) + ','; - newSrc += JSON.stringify(name) + ');\n'; - } - return newSrc; -} - -async function loadClientImport( - url: string, - defaultTransformSource: TransformSourceFunction, -): Promise<{format: string, shortCircuit?: boolean, source: Source}> { - if (stashedGetSource === null) { - throw new Error( - 'Expected getSource to have been called before transformSource', - ); - } - // TODO: Validate that this is another module by calling getFormat. - const {source} = await stashedGetSource( - url, - {format: 'module'}, - stashedGetSource, - ); - const result = await defaultTransformSource( - source, - {format: 'module', url}, - defaultTransformSource, - ); - return {format: 'module', source: result.source}; -} - -async function transformModuleIfNeeded( - source: string, - url: string, - loader: LoadFunction, -): Promise { - // Do a quick check for the exact string. If it doesn't exist, don't - // bother parsing. - if ( - source.indexOf('use client') === -1 && - source.indexOf('use server') === -1 - ) { - return source; - } - - let body; - try { - body = acorn.parse(source, { - ecmaVersion: '2024', - sourceType: 'module', - }).body; - } catch (x) { - // eslint-disable-next-line react-internal/no-production-logging - console.error('Error parsing %s %s', url, x.message); - return source; - } - - let useClient = false; - let useServer = false; - for (let i = 0; i < body.length; i++) { - const node = body[i]; - if (node.type !== 'ExpressionStatement' || !node.directive) { - break; - } - if (node.directive === 'use client') { - useClient = true; - } - if (node.directive === 'use server') { - useServer = true; - } - } - - if (!useClient && !useServer) { - return source; - } - - if (useClient && useServer) { - throw new Error( - 'Cannot have both "use client" and "use server" directives in the same file.', - ); - } - - if (useClient) { - return transformClientModule(body, url, loader); - } - - return transformServerModule(source, body, url, loader); -} - -export async function transformSource( - source: Source, - context: TransformSourceContext, - defaultTransformSource: TransformSourceFunction, -): Promise<{source: Source}> { - const transformed = await defaultTransformSource( - source, - context, - defaultTransformSource, - ); - if (context.format === 'module') { - const transformedSource = transformed.source; - if (typeof transformedSource !== 'string') { - throw new Error('Expected source to have been transformed to a string.'); - } - const newSrc = await transformModuleIfNeeded( - transformedSource, - context.url, - (url: string, ctx: LoadContext, defaultLoad: LoadFunction) => { - return loadClientImport(url, defaultTransformSource); - }, - ); - return {source: newSrc}; - } - return transformed; -} - -export async function load( - url: string, - context: LoadContext, - defaultLoad: LoadFunction, -): Promise<{format: string, shortCircuit?: boolean, source: Source}> { - const result = await defaultLoad(url, context, defaultLoad); - if (result.format === 'module') { - if (typeof result.source !== 'string') { - throw new Error('Expected source to have been loaded into a string.'); - } - const newSrc = await transformModuleIfNeeded( - result.source, - url, - defaultLoad, - ); - return {format: 'module', source: newSrc}; - } - return result; -} diff --git a/packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeRegister.js b/packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeRegister.js deleted file mode 100644 index fa7965cc89945..0000000000000 --- a/packages/react-server-dom-turbopack/src/ReactFlightTurbopackNodeRegister.js +++ /dev/null @@ -1,109 +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. - * - * @flow - */ - -const acorn = require('acorn-loose'); - -const url = require('url'); - -const Module = require('module'); - -module.exports = function register() { - const Server: any = require('react-server-dom-turbopack/server'); - const registerServerReference = Server.registerServerReference; - const createClientModuleProxy = Server.createClientModuleProxy; - - // $FlowFixMe[prop-missing] found when upgrading Flow - const originalCompile = Module.prototype._compile; - - // $FlowFixMe[prop-missing] found when upgrading Flow - Module.prototype._compile = function ( - this: any, - content: string, - filename: string, - ): void { - // Do a quick check for the exact string. If it doesn't exist, don't - // bother parsing. - if ( - content.indexOf('use client') === -1 && - content.indexOf('use server') === -1 - ) { - return originalCompile.apply(this, arguments); - } - - let body; - try { - body = acorn.parse(content, { - ecmaVersion: '2024', - sourceType: 'source', - }).body; - } catch (x) { - console['error']('Error parsing %s %s', url, x.message); - return originalCompile.apply(this, arguments); - } - - let useClient = false; - let useServer = false; - for (let i = 0; i < body.length; i++) { - const node = body[i]; - if (node.type !== 'ExpressionStatement' || !node.directive) { - break; - } - if (node.directive === 'use client') { - useClient = true; - } - if (node.directive === 'use server') { - useServer = true; - } - } - - if (!useClient && !useServer) { - return originalCompile.apply(this, arguments); - } - - if (useClient && useServer) { - throw new Error( - 'Cannot have both "use client" and "use server" directives in the same file.', - ); - } - - if (useClient) { - const moduleId: string = (url.pathToFileURL(filename).href: any); - this.exports = createClientModuleProxy(moduleId); - } - - if (useServer) { - originalCompile.apply(this, arguments); - - const moduleId: string = (url.pathToFileURL(filename).href: any); - - const exports = this.exports; - - // This module is imported server to server, but opts in to exposing functions by - // reference. If there are any functions in the export. - if (typeof exports === 'function') { - // The module exports a function directly, - registerServerReference( - (exports: any), - moduleId, - // Represents the whole Module object instead of a particular import. - null, - ); - } else { - const keys = Object.keys(exports); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const value = exports[keys[i]]; - if (typeof value === 'function') { - registerServerReference((value: any), moduleId, key); - } - } - } - } - }; -}; diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js index eef2e824543e7..0cf2876fedba6 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js @@ -30,7 +30,7 @@ let Suspense; let ReactServerScheduler; let reactServerAct; -describe('ReactFlightDOM', () => { +describe('ReactFlightTurbopackDOM', () => { beforeEach(() => { // For this first reset we are going to load the dom-node version of react-server-dom-turbopack/server // This can be thought of as essentially being the React Server Components scope with react-server @@ -43,7 +43,7 @@ describe('ReactFlightDOM', () => { // Simulate the condition resolution jest.mock('react-server-dom-turbopack/server', () => - require('react-server-dom-turbopack/server.node.unbundled'), + require('react-server-dom-turbopack/server.node'), ); jest.mock('react', () => require('react/react.react-server')); diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMBrowser-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMBrowser-test.js index a47cca7068801..d90e1189d508e 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMBrowser-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMBrowser-test.js @@ -23,7 +23,7 @@ let ReactServerDOMClient; let ReactServerScheduler; let reactServerAct; -describe('ReactFlightDOMBrowser', () => { +describe('ReactFlightTurbopackDOMBrowser', () => { beforeEach(() => { jest.resetModules(); diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js index 67d25c967f472..767e1f1ed0ebc 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js @@ -28,7 +28,7 @@ let ReactServerDOMServer; let ReactServerDOMClient; let use; -describe('ReactFlightDOMEdge', () => { +describe('ReactFlightTurbopackDOMEdge', () => { beforeEach(() => { jest.resetModules(); diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMForm-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMForm-test.js deleted file mode 100644 index e7da697fad8e9..0000000000000 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMForm-test.js +++ /dev/null @@ -1,147 +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. - * - * @emails react-core - */ - -'use strict'; - -import {insertNodesAndExecuteScripts} from 'react-dom/src/test-utils/FizzTestUtils'; - -// Polyfills for test environment -global.ReadableStream = - require('web-streams-polyfill/ponyfill/es6').ReadableStream; -global.TextEncoder = require('util').TextEncoder; -global.TextDecoder = require('util').TextDecoder; - -// Don't wait before processing work on the server. -// TODO: we can replace this with FlightServer.act(). -global.setTimeout = cb => cb(); - -let container; -let serverExports; -let turbopackServerMap; -let React; -let ReactDOMServer; -let ReactServerDOMServer; -let ReactServerDOMClient; - -describe('ReactFlightDOMForm', () => { - beforeEach(() => { - jest.resetModules(); - // Simulate the condition resolution - jest.mock('react', () => require('react/react.react-server')); - jest.mock('react-server-dom-turbopack/server', () => - require('react-server-dom-turbopack/server.edge'), - ); - ReactServerDOMServer = require('react-server-dom-turbopack/server.edge'); - const TurbopackMock = require('./utils/TurbopackMock'); - serverExports = TurbopackMock.serverExports; - turbopackServerMap = TurbopackMock.turbopackServerMap; - __unmockReact(); - jest.resetModules(); - React = require('react'); - ReactServerDOMClient = require('react-server-dom-turbopack/client.edge'); - ReactDOMServer = require('react-dom/server.edge'); - container = document.createElement('div'); - document.body.appendChild(container); - }); - - afterEach(() => { - document.body.removeChild(container); - }); - - async function POST(formData) { - const boundAction = await ReactServerDOMServer.decodeAction( - formData, - turbopackServerMap, - ); - return boundAction(); - } - - function submit(submitter) { - const form = submitter.form || submitter; - if (!submitter.form) { - submitter = undefined; - } - const submitEvent = new Event('submit', {bubbles: true, cancelable: true}); - submitEvent.submitter = submitter; - const returnValue = form.dispatchEvent(submitEvent); - if (!returnValue) { - return; - } - const action = - (submitter && submitter.getAttribute('formaction')) || form.action; - if (!/\s*javascript:/i.test(action)) { - const method = (submitter && submitter.formMethod) || form.method; - const encType = (submitter && submitter.formEnctype) || form.enctype; - if (method === 'post' && encType === 'multipart/form-data') { - let formData; - if (submitter) { - const temp = document.createElement('input'); - temp.name = submitter.name; - temp.value = submitter.value; - submitter.parentNode.insertBefore(temp, submitter); - formData = new FormData(form); - temp.parentNode.removeChild(temp); - } else { - formData = new FormData(form); - } - return POST(formData); - } - throw new Error('Navigate to: ' + action); - } - } - - async function readIntoContainer(stream) { - const reader = stream.getReader(); - let result = ''; - while (true) { - const {done, value} = await reader.read(); - if (done) { - break; - } - result += Buffer.from(value).toString('utf8'); - } - const temp = document.createElement('div'); - temp.innerHTML = result; - insertNodesAndExecuteScripts(temp, container, null); - } - - it('can submit a passed server action without hydrating it', async () => { - let foo = null; - - const serverAction = serverExports(function action(formData) { - foo = formData.get('foo'); - return 'hello'; - }); - function App() { - return ( -
- -
- ); - } - const rscStream = ReactServerDOMServer.renderToReadableStream(); - const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { - moduleMap: null, - moduleLoading: null, - }, - }); - const ssrStream = await ReactDOMServer.renderToReadableStream(response); - await readIntoContainer(ssrStream); - - const form = container.firstChild; - - expect(foo).toBe(null); - - const result = await submit(form); - - expect(result).toBe('hello'); - expect(foo).toBe('bar'); - }); -}); diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMNode-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMNode-test.js index 1276d4d0be40b..a7b6ff75d57ba 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMNode-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMNode-test.js @@ -24,7 +24,7 @@ let use; let ReactServerScheduler; let reactServerAct; -describe('ReactFlightDOMNode', () => { +describe('ReactFlightTurbopackDOMNode', () => { beforeEach(() => { jest.resetModules(); diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReply-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReply-test.js index cf328ab2e8fe3..04abb546df394 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReply-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReply-test.js @@ -23,7 +23,7 @@ let ReactServerDOMServer; let ReactServerDOMClient; let ReactServerScheduler; -describe('ReactFlightDOMReply', () => { +describe('ReactFlightTurbopackDOMReply', () => { beforeEach(() => { jest.resetModules(); diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReplyEdge-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReplyEdge-test.js index 0cd8605c7e8d6..cbc06ef80d503 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReplyEdge-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMReplyEdge-test.js @@ -20,7 +20,7 @@ let turbopackServerMap; let ReactServerDOMServer; let ReactServerDOMClient; -describe('ReactFlightDOMReply', () => { +describe('ReactFlightDOMTurbopackReply', () => { beforeEach(() => { jest.resetModules(); // Simulate the condition resolution diff --git a/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js b/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js index 35c1aae80a02b..5ed6fa5357408 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js +++ b/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js @@ -8,7 +8,6 @@ 'use strict'; const url = require('url'); -const Module = require('module'); let turbopackModuleIdx = 0; const turbopackServerModules = {}; @@ -23,21 +22,9 @@ global.__turbopack_require__ = function (id) { return turbopackClientModules[id] || turbopackServerModules[id]; }; -const previousCompile = Module.prototype._compile; - -const register = require('react-server-dom-turbopack/node-register'); -// Register node compile -register(); - -const nodeCompile = Module.prototype._compile; - -if (previousCompile === nodeCompile) { - throw new Error( - 'Expected the Node loader to register the _compile extension', - ); -} - -Module.prototype._compile = previousCompile; +const Server = require('react-server-dom-turbopack/server'); +const registerServerReference = Server.registerServerReference; +const createClientModuleProxy = Server.createClientModuleProxy; exports.turbopackMap = turbopackClientMap; exports.turbopackModules = turbopackClientModules; @@ -46,20 +33,6 @@ exports.moduleLoading = { prefix: '/prefix/', }; -exports.clientModuleError = function clientModuleError(moduleError) { - const idx = '' + turbopackModuleIdx++; - turbopackErroredModules[idx] = moduleError; - const path = url.pathToFileURL(idx).href; - turbopackClientMap[path] = { - id: idx, - chunks: [], - name: '*', - }; - const mod = new Module(); - nodeCompile.call(mod, '"use client"', idx); - return mod.exports; -}; - exports.clientExports = function clientExports(moduleExports, chunkUrl) { const chunks = []; if (chunkUrl !== undefined) { @@ -107,9 +80,7 @@ exports.clientExports = function clientExports(moduleExports, chunkUrl) { name: 's', }; } - const mod = new Module(); - nodeCompile.call(mod, '"use client"', idx); - return mod.exports; + return createClientModuleProxy(path); }; // This tests server to server references. There's another case of client to server references. @@ -142,8 +113,25 @@ exports.serverExports = function serverExports(moduleExports) { name: 's', }; } - const mod = new Module(); - mod.exports = moduleExports; - nodeCompile.call(mod, '"use server"', idx); - return mod.exports; + + if (typeof exports === 'function') { + // The module exports a function directly, + registerServerReference( + (exports: any), + idx, + // Represents the whole Module object instead of a particular import. + null, + ); + } else { + const keys = Object.keys(exports); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = exports[keys[i]]; + if (typeof value === 'function') { + registerServerReference((value: any), idx, key); + } + } + } + + return moduleExports; }; diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.js deleted file mode 100644 index badc2ed50b691..0000000000000 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.js +++ /dev/null @@ -1,21 +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. - * - * @flow - */ - -export { - renderToPipeableStream, - prerenderToNodeStream, - decodeReplyFromBusboy, - decodeReply, - decodeAction, - decodeFormState, - registerServerReference, - registerClientReference, - createClientModuleProxy, - createTemporaryReferenceSet, -} from './ReactFlightDOMServerNode'; diff --git a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.stable.js b/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.stable.js deleted file mode 100644 index 0d159704067ea..0000000000000 --- a/packages/react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled.stable.js +++ /dev/null @@ -1,20 +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. - * - * @flow - */ - -export { - renderToPipeableStream, - decodeReplyFromBusboy, - decodeReply, - decodeAction, - decodeFormState, - registerServerReference, - registerClientReference, - createClientModuleProxy, - createTemporaryReferenceSet, -} from './ReactFlightDOMServerNode'; diff --git a/packages/react-server-dom-turbopack/static.node.unbundled.js b/packages/react-server-dom-turbopack/static.node.unbundled.js deleted file mode 100644 index b2134459afc7a..0000000000000 --- a/packages/react-server-dom-turbopack/static.node.unbundled.js +++ /dev/null @@ -1,10 +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. - * - * @flow - */ - -export {prerenderToNodeStream} from './src/server/react-flight-dom-server.node.unbundled'; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index ea4d1a034bf47..081b91b9d0b80 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -534,18 +534,6 @@ const bundles = [ wrapWithModuleBoundaries: false, externals: ['react', 'util', 'async_hooks', 'react-dom'], }, - { - bundleTypes: [NODE_DEV, NODE_PROD], - moduleType: RENDERER, - entry: - 'react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled', - name: 'react-server-dom-turbopack-server.node.unbundled', - condition: 'react-server', - global: 'ReactServerDOMServer', - minifyWithProdErrorCodes: false, - wrapWithModuleBoundaries: false, - externals: ['react', 'util', 'async_hooks', 'react-dom'], - }, { bundleTypes: [NODE_DEV, NODE_PROD], moduleType: RENDERER, @@ -577,15 +565,6 @@ const bundles = [ wrapWithModuleBoundaries: false, externals: ['react', 'react-dom', 'util'], }, - { - bundleTypes: [NODE_DEV, NODE_PROD], - moduleType: RENDERER, - entry: 'react-server-dom-turbopack/client.node.unbundled', - global: 'ReactServerDOMClient', - minifyWithProdErrorCodes: false, - wrapWithModuleBoundaries: false, - externals: ['react', 'react-dom', 'util'], - }, { bundleTypes: [NODE_DEV, NODE_PROD], moduleType: RENDERER, @@ -596,35 +575,6 @@ const bundles = [ externals: ['react', 'react-dom'], }, - /******* React Server DOM Turbopack Plugin *******/ - // There is no plugin the moment because Turbopack - // does not expose a plugin interface yet. - - /******* React Server DOM Turbopack Node.js Loader *******/ - { - bundleTypes: [ESM_PROD], - moduleType: RENDERER_UTILS, - entry: 'react-server-dom-turbopack/node-loader', - condition: 'react-server', - global: 'ReactServerTurbopackNodeLoader', - minifyWithProdErrorCodes: false, - wrapWithModuleBoundaries: false, - externals: ['acorn'], - }, - - /******* React Server DOM Turbopack Node.js CommonJS Loader *******/ - { - bundleTypes: [NODE_ES2015], - moduleType: RENDERER_UTILS, - entry: 'react-server-dom-turbopack/src/ReactFlightTurbopackNodeRegister', - name: 'react-server-dom-turbopack-node-register', - condition: 'react-server', - global: 'ReactFlightWebpackNodeRegister', - minifyWithProdErrorCodes: false, - wrapWithModuleBoundaries: false, - externals: ['url', 'module', 'react-server-dom-turbopack/server'], - }, - /******* React Server DOM ESM Server *******/ { bundleTypes: [NODE_DEV, NODE_PROD], diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js index be5706c927c7c..514ecc4567b05 100644 --- a/scripts/shared/inlinedHostConfigs.js +++ b/scripts/shared/inlinedHostConfigs.js @@ -104,49 +104,6 @@ module.exports = [ }, { shortName: 'dom-node-turbopack', - entryPoints: [ - 'react-server-dom-turbopack/client.node.unbundled', - 'react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled', - ], - paths: [ - 'react-dom', - 'react-dom-bindings', - 'react-dom/client', - 'react-dom/profiling', - 'react-dom/server', - 'react-dom/server.node', - 'react-dom/static', - 'react-dom/static.node', - 'react-dom/src/server/react-dom-server.node', - 'react-dom/src/server/ReactDOMFizzServerNode.js', // react-dom/server.node - 'react-dom/src/server/ReactDOMFizzStaticNode.js', - 'react-dom-bindings/src/server/ReactDOMFlightServerHostDispatcher.js', - 'react-dom-bindings/src/server/ReactFlightServerConfigDOM.js', - 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM.js', - 'react-server-dom-turbopack', - 'react-server-dom-turbopack/client.node.unbundled', - 'react-server-dom-turbopack/server', - 'react-server-dom-turbopack/server.node.unbundled', - 'react-server-dom-turbopack/static', - 'react-server-dom-turbopack/static.node.unbundled', - 'react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js', // react-server-dom-turbopack/client.node.unbundled - 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js', - 'react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled', - 'react-server-dom-turbopack/src/server/ReactFlightDOMServerNode.js', // react-server-dom-turbopack/src/server/react-flight-dom-server.node.unbundled - 'react-server-dom-turbopack/node-register', - 'react-server-dom-turbopack/src/ReactFlightTurbopackNodeRegister.js', - 'react-devtools', - 'react-devtools-core', - 'react-devtools-shell', - 'react-devtools-shared', - 'shared/ReactDOMSharedInternals', - 'react-server/src/ReactFlightServerConfigDebugNode.js', - ], - isFlowTyped: true, - isServerSupported: true, - }, - { - shortName: 'dom-node-turbopack-bundled', entryPoints: [ 'react-server-dom-turbopack/client.node', 'react-server-dom-turbopack/src/server/react-flight-dom-server.node', From ab24f643d0809ee09a7499862fef135fb09a0225 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Wed, 21 Aug 2024 07:55:56 -0700 Subject: [PATCH 032/426] [Fizz] use microtasks rather than tasks when scheduling work while prerendering (#30770) Similar to https://github.com/facebook/react/pull/30768 we want to schedule work during prerendering in microtasks both for the root task and pings. We continue to schedule flushes as Tasks to allow as much work to be batched up as possible. --- packages/react-server/src/ReactFizzServer.js | 27 +++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index daea492db5b8e..7ccbd65d16b74 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -38,6 +38,7 @@ import {describeObjectForErrorMessage} from 'shared/ReactSerializationErrors'; import { scheduleWork, + scheduleMicrotask, beginWriting, writeChunk, writeChunkAndReturn, @@ -669,7 +670,11 @@ function pingTask(request: Request, task: Task): void { pingedTasks.push(task); if (request.pingedTasks.length === 1) { request.flushScheduled = request.destination !== null; - scheduleWork(() => performWork(request)); + if (request.trackedPostpones !== null) { + scheduleMicrotask(() => performWork(request)); + } else { + scheduleWork(() => performWork(request)); + } } } @@ -4893,12 +4898,22 @@ function flushCompletedQueues( export function startWork(request: Request): void { request.flushScheduled = request.destination !== null; - if (supportsRequestStorage) { - scheduleWork(() => requestStorage.run(request, performWork, request)); + if (request.trackedPostpones !== null) { + // When prerendering we use microtasks for pinging work + if (supportsRequestStorage) { + scheduleMicrotask(() => + requestStorage.run(request, performWork, request), + ); + } else { + scheduleMicrotask(() => performWork(request)); + } } else { - scheduleWork(() => performWork(request)); - } - if (request.trackedPostpones === null) { + // When rendering/resuming we use regular tasks and we also emit early preloads + if (supportsRequestStorage) { + scheduleWork(() => requestStorage.run(request, performWork, request)); + } else { + scheduleWork(() => performWork(request)); + } // this is either a regular render or a resume. For regular render we want // to call emitEarlyPreloads after the first performWork because we want // are responding to a live request and need to balance sending something early From 1d989965a6aac11d71ecf28030796f5475a86642 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 21 Aug 2024 11:41:55 -0400 Subject: [PATCH 033/426] [ez] Add noformat etc headers into some files These are only needed internally so I'm opting to just do it in the commit artifacts job instead of amending the build config. ghstack-source-id: 6a5382b0287d679f4515d79b140ab8248ce90c6b Pull Request resolved: https://github.com/facebook/react/pull/30775 --- .github/workflows/runtime_commit_artifacts.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 9f786b9b5eccc..073c289843fe1 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -85,6 +85,11 @@ jobs: sed -i -e 's/ @license React*//' \ build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js + - name: Insert @headers into eslint plugin and react-refresh + run: | + sed -i -e 's/ LICENSE file in the root directory of this source tree./ LICENSE file in the root directory of this source tree.\n * \n * @noformat\n * @nolint\n * @lightSyntaxTransform\n * @preventMunge\n * @oncall react_core/' \ + build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ + build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js - name: Move relevant files for React in www into compiled run: | # Move the facebook-www folder into compiled From 985747f81033833dca22f30b0c04704dd4bd3714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 21 Aug 2024 18:17:29 -0400 Subject: [PATCH 034/426] [DevTools] Support REACT_LEGACY_ELEMENT_TYPE for formatting JSX (#30779) DevTools shouldn't use react-is since that's versioned to one version of React. We don't need to since we use all the symbols from shared/ReactSymbols anyway and have a fork of typeOf that can cover both. Now JSX of old React versions show up with proper JSX formatting when inspecting. --- .../__tests__/legacy/inspectElement-test.js | 20 +------ packages/react-devtools-shared/src/utils.js | 57 ++++++++----------- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js index 243759e5b02e7..b5941ee5c6ccc 100644 --- a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js @@ -289,23 +289,9 @@ describe('InspectedElementContext', () => { "preview_long": {boolean: true, number: 123, string: "abc"}, }, }, - "react_element": { - "$$typeof": Dehydrated { - "preview_short": Symbol(react.element), - "preview_long": Symbol(react.element), - }, - "_owner": null, - "_store": Dehydrated { - "preview_short": {…}, - "preview_long": {}, - }, - "key": null, - "props": Dehydrated { - "preview_short": {…}, - "preview_long": {}, - }, - "ref": null, - "type": "span", + "react_element": Dehydrated { + "preview_short": , + "preview_long": , }, "regexp": Dehydrated { "preview_short": /abc/giu, diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 8e6f52f6c0f8a..62ae8070bf020 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -8,26 +8,13 @@ */ import LRU from 'lru-cache'; -import { - isElement, - typeOf, - ContextConsumer, - ContextProvider, - ForwardRef, - Fragment, - Lazy, - Memo, - Portal, - Profiler, - StrictMode, - Suspense, -} from 'react-is'; import { REACT_CONSUMER_TYPE, REACT_CONTEXT_TYPE, REACT_FORWARD_REF_TYPE, REACT_FRAGMENT_TYPE, REACT_LAZY_TYPE, + REACT_ELEMENT_TYPE, REACT_LEGACY_ELEMENT_TYPE, REACT_MEMO_TYPE, REACT_PORTAL_TYPE, @@ -35,9 +22,8 @@ import { REACT_PROVIDER_TYPE, REACT_STRICT_MODE_TYPE, REACT_SUSPENSE_LIST_TYPE, - REACT_SUSPENSE_LIST_TYPE as SuspenseList, REACT_SUSPENSE_TYPE, - REACT_TRACING_MARKER_TYPE as TracingMarker, + REACT_TRACING_MARKER_TYPE, } from 'shared/ReactSymbols'; import {enableRenderableContext} from 'shared/ReactFeatureFlags'; import { @@ -632,10 +618,6 @@ export function getDataType(data: Object): DataType { return 'undefined'; } - if (isElement(data)) { - return 'react_element'; - } - if (typeof HTMLElement !== 'undefined' && data instanceof HTMLElement) { return 'html_element'; } @@ -657,6 +639,12 @@ export function getDataType(data: Object): DataType { return 'number'; } case 'object': + if ( + data.$$typeof === REACT_ELEMENT_TYPE || + data.$$typeof === REACT_LEGACY_ELEMENT_TYPE + ) { + return 'react_element'; + } if (isArray(data)) { return 'array'; } else if (ArrayBuffer.isView(data)) { @@ -717,6 +705,7 @@ function typeOfWithLegacyElementSymbol(object: any): mixed { if (typeof object === 'object' && object !== null) { const $$typeof = object.$$typeof; switch ($$typeof) { + case REACT_ELEMENT_TYPE: case REACT_LEGACY_ELEMENT_TYPE: const type = object.type; @@ -761,31 +750,33 @@ function typeOfWithLegacyElementSymbol(object: any): mixed { export function getDisplayNameForReactElement( element: React$Element, ): string | null { - const elementType = typeOf(element) || typeOfWithLegacyElementSymbol(element); + const elementType = typeOfWithLegacyElementSymbol(element); switch (elementType) { - case ContextConsumer: + case REACT_CONSUMER_TYPE: return 'ContextConsumer'; - case ContextProvider: + case REACT_PROVIDER_TYPE: return 'ContextProvider'; - case ForwardRef: + case REACT_CONTEXT_TYPE: + return 'Context'; + case REACT_FORWARD_REF_TYPE: return 'ForwardRef'; - case Fragment: + case REACT_FRAGMENT_TYPE: return 'Fragment'; - case Lazy: + case REACT_LAZY_TYPE: return 'Lazy'; - case Memo: + case REACT_MEMO_TYPE: return 'Memo'; - case Portal: + case REACT_PORTAL_TYPE: return 'Portal'; - case Profiler: + case REACT_PROFILER_TYPE: return 'Profiler'; - case StrictMode: + case REACT_STRICT_MODE_TYPE: return 'StrictMode'; - case Suspense: + case REACT_SUSPENSE_TYPE: return 'Suspense'; - case SuspenseList: + case REACT_SUSPENSE_LIST_TYPE: return 'SuspenseList'; - case TracingMarker: + case REACT_TRACING_MARKER_TYPE: return 'TracingMarker'; default: const {type} = element; From eb3ad065a10e542eb501bcb7dba7f9617e8c363e Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Thu, 22 Aug 2024 10:17:19 -0400 Subject: [PATCH 035/426] Feature flag: enableSiblingPrerendering (#30761) Adds a new feature flag for an upcoming experiment. No implementation yet. --- packages/shared/ReactFeatureFlags.js | 2 ++ packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js | 1 + packages/shared/forks/ReactFeatureFlags.native-fb.js | 1 + packages/shared/forks/ReactFeatureFlags.native-oss.js | 1 + packages/shared/forks/ReactFeatureFlags.test-renderer.js | 1 + .../shared/forks/ReactFeatureFlags.test-renderer.native-fb.js | 1 + packages/shared/forks/ReactFeatureFlags.test-renderer.www.js | 1 + packages/shared/forks/ReactFeatureFlags.www-dynamic.js | 1 + packages/shared/forks/ReactFeatureFlags.www.js | 1 + 9 files changed, 10 insertions(+) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index c5351d6d92631..673ff9d7e8450 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -148,6 +148,8 @@ export const enableOwnerStacks = __EXPERIMENTAL__; export const enableShallowPropDiffing = false; +export const enableSiblingPrerendering = __EXPERIMENTAL__; + /** * Enables an expiration time for retry lanes to avoid starvation. */ diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index 2426206bc825d..2d49c56377a2f 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -25,3 +25,4 @@ export const enableShallowPropDiffing = __VARIANT__; export const passChildrenWhenCloningPersistedNodes = __VARIANT__; export const enableFabricCompleteRootInCommitPhase = __VARIANT__; export const enableLazyContextPropagation = __VARIANT__; +export const enableSiblingPrerendering = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 3618aa70e7d67..6ba5a79ff0f39 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -27,6 +27,7 @@ export const { enableShallowPropDiffing, passChildrenWhenCloningPersistedNodes, enableLazyContextPropagation, + enableSiblingPrerendering, } = dynamicFlags; // The rest of the flags are static for better dead code elimination. diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 2aae8bd3d1c65..4e50442c2579f 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -84,6 +84,7 @@ export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; export const useModernStrictMode = true; +export const enableSiblingPrerendering = false; // Profiling Only export const enableProfilerTimer = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index c44e7014fc444..ae211b9ec4639 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -80,6 +80,7 @@ export const enableAddPropertiesFastPath = false; export const renameElementSymbol = true; export const enableShallowPropDiffing = false; +export const enableSiblingPrerendering = __EXPERIMENTAL__; // TODO: This must be in sync with the main ReactFeatureFlags file because // the Test Renderer's value must be the same as the one used by the diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index bc7ddf85acc03..ebc3ddab2a551 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -80,6 +80,7 @@ export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; export const useModernStrictMode = true; export const enableFabricCompleteRootInCommitPhase = false; +export const enableSiblingPrerendering = false; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 57f60c24aef45..a378ab3edf17c 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -94,6 +94,7 @@ export const renameElementSymbol = false; export const enableObjectFiber = false; export const enableOwnerStacks = false; export const enableShallowPropDiffing = false; +export const enableSiblingPrerendering = false; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index e2f2751f0c2c8..d6e11f92649ba 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -41,6 +41,7 @@ export const enableDebugTracing = __EXPERIMENTAL__; export const enableSchedulingProfiler = __VARIANT__; export const enableInfiniteRenderLoopDetection = __VARIANT__; +export const enableSiblingPrerendering = __VARIANT__; // TODO: These flags are hard-coded to the default values used in open source. // Update the tests so that they pass in either mode, then set these diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 465fa58590bcc..e207dbb71b669 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -35,6 +35,7 @@ export const { retryLaneExpirationMs, syncLaneExpirationMs, transitionLaneExpirationMs, + enableSiblingPrerendering, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build. From f7bb717e9e9f876c6a466a5f6d31004c7f7590c5 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 21 Aug 2024 14:07:11 -0700 Subject: [PATCH 036/426] [compiler] Repro for missing memoization due to inferred mutation This fixture bails out on ValidatePreserveExistingMemo but would ideally memoize since the original memoization is safe. It's trivial to make it pass by commenting out the commented line (`LogEvent.log(() => object)`). I would expect the compiler to infer this as possible mutation of `logData`, since `object` captures a reference to `logData`. But somehow `logData` is getting memoized successfully, but we still infer the callback, `setCurrentIndex`, as having a mutable range that extends to the `setCurrentIndex()` call after the useCallback. ghstack-source-id: 4f82e345102f82f6da74de3f9014af263d016762 Pull Request resolved: https://github.com/facebook/react/pull/30764 --- .../ValidatePreservedManualMemoization.ts | 6 +- ...from-inferred-mutation-in-logger.expect.md | 83 +++++++++++++++++++ ...zation-from-inferred-mutation-in-logger.js | 46 ++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 50d1c986cea5a..7af4aaaccd7ab 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -23,7 +23,7 @@ import { ScopeId, SourceLocation, } from '../HIR'; -import {printManualMemoDependency} from '../HIR/PrintHIR'; +import {printIdentifier, printManualMemoDependency} from '../HIR/PrintHIR'; import {eachInstructionValueOperand} from '../HIR/visitors'; import {collectMaybeMemoDependencies} from '../Inference/DropManualMemoization'; import { @@ -537,7 +537,9 @@ class Visitor extends ReactiveFunctionVisitor { state.errors.push({ reason: 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output.', - description: null, + description: DEBUG + ? `${printIdentifier(identifier)} was not memoized` + : null, severity: ErrorSeverity.CannotPreserveMemoization, loc, suggestions: null, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md new file mode 100644 index 0000000000000..9010607496478 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md @@ -0,0 +1,83 @@ + +## Input + +```javascript +// @flow @validatePreserveExistingMemoizationGuarantees +import {useFragment} from 'react-relay'; +import LogEvent from 'LogEvent'; +import {useCallback, useMemo} from 'react'; + +component Component(id) { + const {data} = useFragment(); + const items = data.items.edges; + + const [prevId, setPrevId] = useState(id); + const [index, setIndex] = useState(0); + + const logData = useMemo(() => { + const item = items[index]; + return { + key: item.key ?? '', + }; + }, [index, items]); + + const setCurrentIndex = useCallback( + (index: number) => { + const object = { + tracking: logData.key, + }; + // We infer that this may mutate `object`, which in turn aliases + // data from `logData`, such that `logData` may be mutated. + LogEvent.log(() => object); + setIndex(index); + }, + [index, logData, items] + ); + + if (prevId !== id) { + setPrevId(id); + setCurrentIndex(0); + } + + return ( + + ); +} + +``` + + +## Error + +``` + 19 | + 20 | const setCurrentIndex = useCallback( +> 21 | (index: number) => { + | ^^^^^^^^^^^^^^^^^^^^ +> 22 | const object = { + | ^^^^^^^^^^^^^^^^^^^^^^ +> 23 | tracking: logData.key, + | ^^^^^^^^^^^^^^^^^^^^^^ +> 24 | }; + | ^^^^^^^^^^^^^^^^^^^^^^ +> 25 | // We infer that this may mutate `object`, which in turn aliases + | ^^^^^^^^^^^^^^^^^^^^^^ +> 26 | // data from `logData`, such that `logData` may be mutated. + | ^^^^^^^^^^^^^^^^^^^^^^ +> 27 | LogEvent.log(() => object); + | ^^^^^^^^^^^^^^^^^^^^^^ +> 28 | setIndex(index); + | ^^^^^^^^^^^^^^^^^^^^^^ +> 29 | }, + | ^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (21:29) + 30 | [index, logData, items] + 31 | ); + 32 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js new file mode 100644 index 0000000000000..b4b33303767c1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js @@ -0,0 +1,46 @@ +// @flow @validatePreserveExistingMemoizationGuarantees +import {useFragment} from 'react-relay'; +import LogEvent from 'LogEvent'; +import {useCallback, useMemo} from 'react'; + +component Component(id) { + const {data} = useFragment(); + const items = data.items.edges; + + const [prevId, setPrevId] = useState(id); + const [index, setIndex] = useState(0); + + const logData = useMemo(() => { + const item = items[index]; + return { + key: item.key ?? '', + }; + }, [index, items]); + + const setCurrentIndex = useCallback( + (index: number) => { + const object = { + tracking: logData.key, + }; + // We infer that this may mutate `object`, which in turn aliases + // data from `logData`, such that `logData` may be mutated. + LogEvent.log(() => object); + setIndex(index); + }, + [index, logData, items] + ); + + if (prevId !== id) { + setPrevId(id); + setCurrentIndex(0); + } + + return ( + + ); +} From 0ef00b3e17447ae94dc5701a5ad410c137680d86 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 21 Aug 2024 14:07:12 -0700 Subject: [PATCH 037/426] [compiler] Transitively freezing functions marks values as frozen, not effects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fixture from the previous PR was getting inconsistent behavior because of the following: 1. Create an object in a useMemo 2. Create a callback in a useCallback, where the callback captures the object from (1) into a local object, then passes that local object into a logging method. We have to assume the logging method could modify the local object, and transitively, the object from (1). 3. Call the callback during render. 4. Pass the callback to JSX. We correctly infer that the object from (1) is captured and modified in (2). However, in (4) we transitively freeze the callback. When transitively freezing functions we were previously doing two things: updating our internal abstract model of the program values to reflect the values as being frozen *and* also updating function operands to change their effects to freeze. As the case above demonstrates, that can clobber over information about real potential mutability. The potential fix here is to only walk our abstract value model to mark values as frozen, but _not_ override operand effects. Conceptually, this is a forward data flow propagation — but walking backward to update effects is pushing information backwards in the algorithm. An alternative would be to mark that data was propagated backwards, and trigger another loop over the CFG to propagate information forward again given the updated effects. But the fix in this PR is more correct. ghstack-source-id: c05e716f37827cb5515a059a1f0e8e8ff94b91df Pull Request resolved: https://github.com/facebook/react/pull/30766 --- .../src/Inference/InferReferenceEffects.ts | 59 +++++++++++-------- ...mutate-global-in-effect-fixpoint.expect.md | 53 +++++++++-------- ...from-inferred-mutation-in-logger.expect.md | 51 ++++++++-------- ...zation-from-inferred-mutation-in-logger.js | 7 +-- 4 files changed, 89 insertions(+), 81 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 4cce942c18154..8aa82469bdec4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -453,6 +453,37 @@ class InferenceState { } } + freezeValues(values: Set, reason: Set): void { + for (const value of values) { + this.#values.set(value, { + kind: ValueKind.Frozen, + reason, + context: new Set(), + }); + if (value.kind === 'FunctionExpression') { + if ( + this.#env.config.enablePreserveExistingMemoizationGuarantees || + this.#env.config.enableTransitivelyFreezeFunctionExpressions + ) { + if (value.kind === 'FunctionExpression') { + /* + * We want to freeze the captured values, not mark the operands + * themselves as frozen. There could be mutations that occur + * before the freeze we are processing, and it would be invalid + * to overwrite those mutations as a freeze. + */ + for (const operand of eachInstructionValueOperand(value)) { + const operandValues = this.#variables.get(operand.identifier.id); + if (operandValues !== undefined) { + this.freezeValues(operandValues, reason); + } + } + } + } + } + } + } + reference( place: Place, effectKind: Effect, @@ -482,29 +513,7 @@ class InferenceState { reason: reasonSet, context: new Set(), }; - values.forEach(value => { - this.#values.set(value, { - kind: ValueKind.Frozen, - reason: reasonSet, - context: new Set(), - }); - - if ( - this.#env.config.enablePreserveExistingMemoizationGuarantees || - this.#env.config.enableTransitivelyFreezeFunctionExpressions - ) { - if (value.kind === 'FunctionExpression') { - for (const operand of eachInstructionValueOperand(value)) { - this.referenceAndRecordEffects( - operand, - Effect.Freeze, - ValueReason.Other, - [], - ); - } - } - } - }); + this.freezeValues(values, reasonSet); } else { effect = Effect.Read; } @@ -1241,6 +1250,7 @@ function inferBlock( case 'ObjectMethod': case 'FunctionExpression': { let hasMutableOperand = false; + const mutableOperands: Array = []; for (const operand of eachInstructionOperand(instr)) { state.referenceAndRecordEffects( operand, @@ -1248,6 +1258,9 @@ function inferBlock( ValueReason.Other, [], ); + if (isMutableEffect(operand.effect, operand.loc)) { + mutableOperands.push(operand); + } hasMutableOperand ||= isMutableEffect(operand.effect, operand.loc); /** diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md index 670236e1f7498..942daec1dd08c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-mutate-global-in-effect-fixpoint.expect.md @@ -46,54 +46,57 @@ import { useEffect, useState } from "react"; let someGlobal = { value: null }; function Component() { - const $ = _c(6); + const $ = _c(7); const [state, setState] = useState(someGlobal); - - let x = someGlobal; - while (x == null) { - x = someGlobal; - } - - const y = x; let t0; let t1; + let t2; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = () => { + let x = someGlobal; + while (x == null) { + x = someGlobal; + } + + const y = x; + t0 = useEffect; + t1 = () => { y.value = "hello"; }; - t1 = []; + t2 = []; $[0] = t0; $[1] = t1; + $[2] = t2; } else { t0 = $[0]; t1 = $[1]; + t2 = $[2]; } - useEffect(t0, t1); - let t2; + t0(t1, t2); let t3; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = () => { + let t4; + if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + t3 = () => { setState(someGlobal.value); }; - t3 = [someGlobal]; - $[2] = t2; + t4 = [someGlobal]; $[3] = t3; + $[4] = t4; } else { - t2 = $[2]; t3 = $[3]; + t4 = $[4]; } - useEffect(t2, t3); + useEffect(t3, t4); - const t4 = String(state); - let t5; - if ($[4] !== t4) { - t5 =
{t4}
; - $[4] = t4; + const t5 = String(state); + let t6; + if ($[5] !== t5) { + t6 =
{t5}
; $[5] = t5; + $[6] = t6; } else { - t5 = $[5]; + t6 = $[6]; } - return t5; + return t6; } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md index 9010607496478..39e4c5f0c3253 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.expect.md @@ -8,16 +8,14 @@ import LogEvent from 'LogEvent'; import {useCallback, useMemo} from 'react'; component Component(id) { - const {data} = useFragment(); - const items = data.items.edges; + const items = useFragment(); - const [prevId, setPrevId] = useState(id); const [index, setIndex] = useState(0); const logData = useMemo(() => { const item = items[index]; return { - key: item.key ?? '', + key: item.key, }; }, [index, items]); @@ -35,7 +33,6 @@ component Component(id) { ); if (prevId !== id) { - setPrevId(id); setCurrentIndex(0); } @@ -55,29 +52,27 @@ component Component(id) { ## Error ``` - 19 | - 20 | const setCurrentIndex = useCallback( -> 21 | (index: number) => { - | ^^^^^^^^^^^^^^^^^^^^ -> 22 | const object = { - | ^^^^^^^^^^^^^^^^^^^^^^ -> 23 | tracking: logData.key, - | ^^^^^^^^^^^^^^^^^^^^^^ -> 24 | }; - | ^^^^^^^^^^^^^^^^^^^^^^ -> 25 | // We infer that this may mutate `object`, which in turn aliases - | ^^^^^^^^^^^^^^^^^^^^^^ -> 26 | // data from `logData`, such that `logData` may be mutated. - | ^^^^^^^^^^^^^^^^^^^^^^ -> 27 | LogEvent.log(() => object); - | ^^^^^^^^^^^^^^^^^^^^^^ -> 28 | setIndex(index); - | ^^^^^^^^^^^^^^^^^^^^^^ -> 29 | }, - | ^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (21:29) - 30 | [index, logData, items] - 31 | ); - 32 | + 9 | const [index, setIndex] = useState(0); + 10 | +> 11 | const logData = useMemo(() => { + | ^^^^^^^^^^^^^^^ +> 12 | const item = items[index]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 13 | return { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 14 | key: item.key, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 15 | }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 16 | }, [index, items]); + | ^^^^^^^^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (11:16) + +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This dependency may be mutated later, which could cause the value to change unexpectedly (28:28) + +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (19:27) + 17 | + 18 | const setCurrentIndex = useCallback( + 19 | (index: number) => { ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js index b4b33303767c1..34a9a12882188 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-inferred-mutation-in-logger.js @@ -4,16 +4,14 @@ import LogEvent from 'LogEvent'; import {useCallback, useMemo} from 'react'; component Component(id) { - const {data} = useFragment(); - const items = data.items.edges; + const items = useFragment(); - const [prevId, setPrevId] = useState(id); const [index, setIndex] = useState(0); const logData = useMemo(() => { const item = items[index]; return { - key: item.key ?? '', + key: item.key, }; }, [index, items]); @@ -31,7 +29,6 @@ component Component(id) { ); if (prevId !== id) { - setPrevId(id); setCurrentIndex(0); } From 689c6bd3fd138ec6c21c54e741da168bdd0c0616 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 21 Aug 2024 15:45:30 -0700 Subject: [PATCH 038/426] [compiler][wip] Environment option for resolving imported module types Adds a new Environment config option which allows specifying a function that is called to resolve types of imported modules. The function is passed the name of the imported module (the RHS of the import stmt) and can return a TypeConfig, which is a recursive type of the following form: * Object of valid identifier keys (or "*" for wildcard) and values that are TypeConfigs * Function with various properties, whose return type is a TypeConfig * or a reference to a builtin type using one of a small list (currently Ref, Array, MixedReadonly, Primitive) Rather than have to eagerly supply all known types (most of which may not be used) when creating the config, this function can do so lazily. During InferTypes we call `getGlobalDeclaration()` to resolve global types. Originally this was just for known react modules, but if the new config option is passed we also call it to see if it can resolve a type. For `import {name} from 'module'` syntax, we first resolve the module type and then call `getPropertyType(moduleType, 'name')` to attempt to retrieve the property of the module (the module would obviously have to be typed as an object type for this to have a chance of yielding a result). If the module type is returned as null, or the property doesn't exist, we fall through to the original checking of whether the name was hook-like. TODO: * testing * cache the results of modules so we don't have to re-parse/install their types on each LoadGlobal of the same module * decide what to do if the module types are invalid. probably better to fatal rather than bail out, since this would indicate an invalid configuration. ghstack-source-id: bfdbf67e3dd0cbfd511bed0bd6ba92266cf99ab8 Pull Request resolved: https://github.com/facebook/react/pull/30771 --- .../src/HIR/Environment.ts | 71 ++++++- .../src/HIR/Globals.ts | 76 +++++++ .../src/HIR/HIR.ts | 19 ++ .../src/HIR/TypeSchema.ts | 105 ++++++++++ .../src/Inference/DropManualMemoization.ts | 2 +- .../src/TypeInference/InferTypes.ts | 2 +- ...ed-scope-declarations-and-locals.expect.md | 4 + ...ing-mixed-scope-declarations-and-locals.js | 2 + .../compiler/optional-call-logical.expect.md | 4 + .../compiler/optional-call-logical.js | 2 + ...ject-method-calls-mutable-lambda.expect.md | 4 + ...only-object-method-calls-mutable-lambda.js | 2 + .../readonly-object-method-calls.expect.md | 4 + .../compiler/readonly-object-method-calls.js | 2 + .../tagged-template-in-hook.expect.md | 4 + .../compiler/tagged-template-in-hook.js | 2 + ...type-provider-log-default-import.expect.md | 147 ++++++++++++++ .../type-provider-log-default-import.tsx | 30 +++ .../compiler/type-provider-log.expect.md | 145 ++++++++++++++ .../fixtures/compiler/type-provider-log.tsx | 29 +++ ...r-store-capture-namespace-import.expect.md | 185 ++++++++++++++++++ ...rovider-store-capture-namespace-import.tsx | 35 ++++ .../type-provider-store-capture.expect.md | 185 ++++++++++++++++++ .../compiler/type-provider-store-capture.tsx | 35 ++++ compiler/packages/snap/src/compiler.ts | 45 ++--- compiler/packages/snap/src/constants.ts | 1 + compiler/packages/snap/src/runner-worker.ts | 6 + .../sprout/shared-runtime-type-provider.ts | 69 +++++++ .../snap/src/sprout/shared-runtime.ts | 9 + 29 files changed, 1190 insertions(+), 36 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.tsx create mode 100644 compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index a5614ac244a14..12c741641c7e0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -17,6 +17,7 @@ import { Global, GlobalRegistry, installReAnimatedTypes, + installTypeConfig, } from './Globals'; import { BlockId, @@ -28,6 +29,7 @@ import { NonLocalBinding, PolyType, ScopeId, + SourceLocation, Type, ValidatedIdentifier, ValueKind, @@ -45,6 +47,7 @@ import { addHook, } from './ObjectShape'; import {Scope as BabelScope} from '@babel/traverse'; +import {TypeSchema} from './TypeSchema'; export const ExternalFunctionSchema = z.object({ // Source for the imported module that exports the `importSpecifierName` functions @@ -137,6 +140,12 @@ export type Hook = z.infer; const EnvironmentConfigSchema = z.object({ customHooks: z.map(z.string(), HookSchema).optional().default(new Map()), + /** + * A function that, given the name of a module, can optionally return a description + * of that module's type signature. + */ + moduleTypeProvider: z.nullable(z.function().args(z.string())).default(null), + /** * A list of functions which the application compiles as macros, where * the compiler must ensure they are not compiled to rename the macro or separate the @@ -577,6 +586,7 @@ export function printFunctionType(type: ReactFunctionType): string { export class Environment { #globals: GlobalRegistry; #shapes: ShapeRegistry; + #moduleTypes: Map = new Map(); #nextIdentifer: number = 0; #nextBlock: number = 0; #nextScope: number = 0; @@ -698,7 +708,40 @@ export class Environment { return this.#outlinedFunctions; } - getGlobalDeclaration(binding: NonLocalBinding): Global | null { + #resolveModuleType(moduleName: string, loc: SourceLocation): Global | null { + if (this.config.moduleTypeProvider == null) { + return null; + } + let moduleType = this.#moduleTypes.get(moduleName); + if (moduleType === undefined) { + const unparsedModuleConfig = this.config.moduleTypeProvider(moduleName); + if (unparsedModuleConfig != null) { + const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig); + if (!parsedModuleConfig.success) { + CompilerError.throwInvalidConfig({ + reason: `Could not parse module type, the configured \`moduleTypeProvider\` function returned an invalid module description`, + description: parsedModuleConfig.error.toString(), + loc, + }); + } + const moduleConfig = parsedModuleConfig.data; + moduleType = installTypeConfig( + this.#globals, + this.#shapes, + moduleConfig, + ); + } else { + moduleType = null; + } + this.#moduleTypes.set(moduleName, moduleType); + } + return moduleType; + } + + getGlobalDeclaration( + binding: NonLocalBinding, + loc: SourceLocation, + ): Global | null { if (this.config.hookPattern != null) { const match = new RegExp(this.config.hookPattern).exec(binding.name); if ( @@ -736,6 +779,17 @@ export class Environment { (isHookName(binding.imported) ? this.#getCustomHookType() : null) ); } else { + const moduleType = this.#resolveModuleType(binding.module, loc); + if (moduleType !== null) { + const importedType = this.getPropertyType( + moduleType, + binding.imported, + ); + if (importedType != null) { + return importedType; + } + } + /** * For modules we don't own, we look at whether the original name or import alias * are hook-like. Both of the following are likely hooks so we would return a hook @@ -758,6 +812,17 @@ export class Environment { (isHookName(binding.name) ? this.#getCustomHookType() : null) ); } else { + const moduleType = this.#resolveModuleType(binding.module, loc); + if (moduleType !== null) { + if (binding.kind === 'ImportDefault') { + const defaultType = this.getPropertyType(moduleType, 'default'); + if (defaultType !== null) { + return defaultType; + } + } else { + return moduleType; + } + } return isHookName(binding.name) ? this.#getCustomHookType() : null; } } @@ -767,9 +832,7 @@ export class Environment { #isKnownReactModule(moduleName: string): boolean { return ( moduleName.toLowerCase() === 'react' || - moduleName.toLowerCase() === 'react-dom' || - (this.config.enableSharedRuntime__testonly && - moduleName === 'shared-runtime') + moduleName.toLowerCase() === 'react-dom' ); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts index e9066f85b8193..2812394300ad5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts @@ -9,6 +9,7 @@ import {Effect, ValueKind, ValueReason} from './HIR'; import { BUILTIN_SHAPES, BuiltInArrayId, + BuiltInMixedReadonlyId, BuiltInUseActionStateId, BuiltInUseContextHookId, BuiltInUseEffectHookId, @@ -25,6 +26,8 @@ import { addObject, } from './ObjectShape'; import {BuiltInType, PolyType} from './Types'; +import {TypeConfig} from './TypeSchema'; +import {assertExhaustive} from '../Utils/utils'; /* * This file exports types and defaults for JavaScript global objects. @@ -528,6 +531,79 @@ DEFAULT_GLOBALS.set( addObject(DEFAULT_SHAPES, 'global', TYPED_GLOBALS), ); +export function installTypeConfig( + globals: GlobalRegistry, + shapes: ShapeRegistry, + typeConfig: TypeConfig, +): Global { + switch (typeConfig.kind) { + case 'type': { + switch (typeConfig.name) { + case 'Array': { + return {kind: 'Object', shapeId: BuiltInArrayId}; + } + case 'MixedReadonly': { + return {kind: 'Object', shapeId: BuiltInMixedReadonlyId}; + } + case 'Primitive': { + return {kind: 'Primitive'}; + } + case 'Ref': { + return {kind: 'Object', shapeId: BuiltInUseRefId}; + } + case 'Any': { + return {kind: 'Poly'}; + } + default: { + assertExhaustive( + typeConfig.name, + `Unexpected type '${(typeConfig as any).name}'`, + ); + } + } + } + case 'function': { + return addFunction(shapes, [], { + positionalParams: typeConfig.positionalParams, + restParam: typeConfig.restParam, + calleeEffect: typeConfig.calleeEffect, + returnType: installTypeConfig(globals, shapes, typeConfig.returnType), + returnValueKind: typeConfig.returnValueKind, + noAlias: typeConfig.noAlias === true, + mutableOnlyIfOperandsAreMutable: + typeConfig.mutableOnlyIfOperandsAreMutable === true, + }); + } + case 'hook': { + return addHook(shapes, { + hookKind: 'Custom', + positionalParams: typeConfig.positionalParams ?? [], + restParam: typeConfig.restParam ?? Effect.Freeze, + calleeEffect: Effect.Read, + returnType: installTypeConfig(globals, shapes, typeConfig.returnType), + returnValueKind: typeConfig.returnValueKind ?? ValueKind.Frozen, + noAlias: typeConfig.noAlias === true, + }); + } + case 'object': { + return addObject( + shapes, + null, + Object.entries(typeConfig.properties ?? {}).map(([key, value]) => [ + key, + installTypeConfig(globals, shapes, value), + ]), + ); + } + default: { + assertExhaustive( + typeConfig, + `Unexpected type kind '${(typeConfig as any).kind}'`, + ); + } + } +} + export function installReAnimatedTypes( globals: GlobalRegistry, registry: ShapeRegistry, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 0810130102b0e..e56c002c513bd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -12,6 +12,7 @@ import {assertExhaustive} from '../Utils/utils'; import {Environment, ReactFunctionType} from './Environment'; import {HookKind} from './ObjectShape'; import {Type, makeType} from './Types'; +import {z} from 'zod'; /* * ******************************************************************************************* @@ -1360,6 +1361,15 @@ export enum ValueKind { Context = 'context', } +export const ValueKindSchema = z.enum([ + ValueKind.MaybeFrozen, + ValueKind.Frozen, + ValueKind.Primitive, + ValueKind.Global, + ValueKind.Mutable, + ValueKind.Context, +]); + // The effect with which a value is modified. export enum Effect { // Default value: not allowed after lifetime inference @@ -1389,6 +1399,15 @@ export enum Effect { Store = 'store', } +export const EffectSchema = z.enum([ + Effect.Read, + Effect.Mutate, + Effect.ConditionallyMutate, + Effect.Capture, + Effect.Store, + Effect.Freeze, +]); + export function isMutableEffect( effect: Effect, location: SourceLocation, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts new file mode 100644 index 0000000000000..362328db72155 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/TypeSchema.ts @@ -0,0 +1,105 @@ +/** + * 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 {isValidIdentifier} from '@babel/types'; +import {z} from 'zod'; +import {Effect, ValueKind} from '..'; +import {EffectSchema, ValueKindSchema} from './HIR'; + +export type ObjectPropertiesConfig = {[key: string]: TypeConfig}; +export const ObjectPropertiesSchema: z.ZodType = z + .record( + z.string(), + z.lazy(() => TypeSchema), + ) + .refine(record => { + return Object.keys(record).every( + key => key === '*' || key === 'default' || isValidIdentifier(key), + ); + }, 'Expected all "object" property names to be valid identifier, `*` to match any property, of `default` to define a module default export'); + +export type ObjectTypeConfig = { + kind: 'object'; + properties: ObjectPropertiesConfig | null; +}; +export const ObjectTypeSchema: z.ZodType = z.object({ + kind: z.literal('object'), + properties: ObjectPropertiesSchema.nullable(), +}); + +export type FunctionTypeConfig = { + kind: 'function'; + positionalParams: Array; + restParam: Effect | null; + calleeEffect: Effect; + returnType: TypeConfig; + returnValueKind: ValueKind; + noAlias?: boolean | null | undefined; + mutableOnlyIfOperandsAreMutable?: boolean | null | undefined; +}; +export const FunctionTypeSchema: z.ZodType = z.object({ + kind: z.literal('function'), + positionalParams: z.array(EffectSchema), + restParam: EffectSchema.nullable(), + calleeEffect: EffectSchema, + returnType: z.lazy(() => TypeSchema), + returnValueKind: ValueKindSchema, + noAlias: z.boolean().nullable().optional(), + mutableOnlyIfOperandsAreMutable: z.boolean().nullable().optional(), +}); + +export type HookTypeConfig = { + kind: 'hook'; + positionalParams?: Array | null | undefined; + restParam?: Effect | null | undefined; + returnType: TypeConfig; + returnValueKind?: ValueKind | null | undefined; + noAlias?: boolean | null | undefined; +}; +export const HookTypeSchema: z.ZodType = z.object({ + kind: z.literal('hook'), + positionalParams: z.array(EffectSchema).nullable().optional(), + restParam: EffectSchema.nullable().optional(), + returnType: z.lazy(() => TypeSchema), + returnValueKind: ValueKindSchema.nullable().optional(), + noAlias: z.boolean().nullable().optional(), +}); + +export type BuiltInTypeConfig = + | 'Any' + | 'Ref' + | 'Array' + | 'Primitive' + | 'MixedReadonly'; +export const BuiltInTypeSchema: z.ZodType = z.union([ + z.literal('Any'), + z.literal('Ref'), + z.literal('Array'), + z.literal('Primitive'), + z.literal('MixedReadonly'), +]); + +export type TypeReferenceConfig = { + kind: 'type'; + name: BuiltInTypeConfig; +}; +export const TypeReferenceSchema: z.ZodType = z.object({ + kind: z.literal('type'), + name: BuiltInTypeSchema, +}); + +export type TypeConfig = + | ObjectTypeConfig + | FunctionTypeConfig + | HookTypeConfig + | TypeReferenceConfig; +export const TypeSchema: z.ZodType = z.union([ + ObjectTypeSchema, + FunctionTypeSchema, + HookTypeSchema, + TypeReferenceSchema, +]); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index 2d9e21af1d61b..c9d2a7e1412c3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -127,7 +127,7 @@ function collectTemporaries( break; } case 'LoadGlobal': { - const global = env.getGlobalDeclaration(value.binding); + const global = env.getGlobalDeclaration(value.binding, value.loc); const hookKind = global !== null ? getHookKindForType(env, global) : null; const lvalId = instr.lvalue.identifier.id; if (hookKind === 'useMemo' || hookKind === 'useCallback') { diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index 0b8949e1977ff..4dfeb676a3d0b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -227,7 +227,7 @@ function* generateInstructionTypes( } case 'LoadGlobal': { - const globalType = env.getGlobalDeclaration(value.binding); + const globalType = env.getGlobalDeclaration(value.binding, value.loc); if (globalType) { yield equation(left, globalType); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md index ed566a605fd5a..f69149aba4175 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.expect.md @@ -2,6 +2,8 @@ ## Input ```javascript +import {useFragment} from 'shared-runtime'; + function Component(props) { const post = useFragment( graphql` @@ -36,6 +38,8 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; +import { useFragment } from "shared-runtime"; + function Component(props) { const $ = _c(4); const post = useFragment( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.js index f44fe5c57baf3..5d1377c458855 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-mixed-scope-declarations-and-locals.js @@ -1,3 +1,5 @@ +import {useFragment} from 'shared-runtime'; + function Component(props) { const post = useFragment( graphql` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.expect.md index 4dc011c85f420..fa6f8cd9bc66c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.expect.md @@ -2,6 +2,8 @@ ## Input ```javascript +import {useFragment} from 'shared-runtime'; + function Component(props) { const item = useFragment( graphql` @@ -20,6 +22,8 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; +import { useFragment } from "shared-runtime"; + function Component(props) { const $ = _c(2); const item = useFragment( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.js index fac4efc9ba90b..6fa11a2dab494 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-logical.js @@ -1,3 +1,5 @@ +import {useFragment} from 'shared-runtime'; + function Component(props) { const item = useFragment( graphql` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.expect.md index 0cbd9caf169f0..3abd8cac949c3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.expect.md @@ -2,6 +2,8 @@ ## Input ```javascript +import {useFragment} from 'shared-runtime'; + function Component(props) { const x = makeObject(); const user = useFragment( @@ -28,6 +30,8 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; +import { useFragment } from "shared-runtime"; + function Component(props) { const $ = _c(3); const x = makeObject(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.js index d78be74ac9957..2658a048939d7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls-mutable-lambda.js @@ -1,3 +1,5 @@ +import {useFragment} from 'shared-runtime'; + function Component(props) { const x = makeObject(); const user = useFragment( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.expect.md index 1a5f49631f661..05ab1c533b9b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.expect.md @@ -2,6 +2,8 @@ ## Input ```javascript +import {useFragment} from 'shared-runtime'; + function Component(props) { const user = useFragment( graphql` @@ -26,6 +28,8 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; +import { useFragment } from "shared-runtime"; + function Component(props) { const $ = _c(5); const user = useFragment( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.js index 7cccb397cabb2..bb1e52dc7645c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/readonly-object-method-calls.js @@ -1,3 +1,5 @@ +import {useFragment} from 'shared-runtime'; + function Component(props) { const user = useFragment( graphql` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.expect.md index 3ffc93ada58ea..d52a7713bb875 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.expect.md @@ -2,6 +2,8 @@ ## Input ```javascript +import {useFragment} from 'shared-runtime'; + function Component(props) { const user = useFragment( graphql` @@ -19,6 +21,8 @@ function Component(props) { ## Code ```javascript +import { useFragment } from "shared-runtime"; + function Component(props) { const user = useFragment( graphql` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.js index cb31d2978a610..dbcd2b6d21803 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/tagged-template-in-hook.js @@ -1,3 +1,5 @@ +import {useFragment} from 'shared-runtime'; + function Component(props) { const user = useFragment( graphql` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md new file mode 100644 index 0000000000000..54d5be2d6bf44 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md @@ -0,0 +1,147 @@ + +## Input + +```javascript +import {useMemo} from 'react'; +import {ValidateMemoization} from 'shared-runtime'; +import typedLog from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + typedLog(item1, item2); + + return ( + <> + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useMemo } from "react"; +import { ValidateMemoization } from "shared-runtime"; +import typedLog from "shared-runtime"; + +export function Component(t0) { + const $ = _c(17); + const { a, b } = t0; + let t1; + let t2; + if ($[0] !== a) { + t2 = { a }; + $[0] = a; + $[1] = t2; + } else { + t2 = $[1]; + } + t1 = t2; + const item1 = t1; + let t3; + let t4; + if ($[2] !== b) { + t4 = { b }; + $[2] = b; + $[3] = t4; + } else { + t4 = $[3]; + } + t3 = t4; + const item2 = t3; + typedLog(item1, item2); + let t5; + if ($[4] !== a) { + t5 = [a]; + $[4] = a; + $[5] = t5; + } else { + t5 = $[5]; + } + let t6; + if ($[6] !== t5 || $[7] !== item1) { + t6 = ; + $[6] = t5; + $[7] = item1; + $[8] = t6; + } else { + t6 = $[8]; + } + let t7; + if ($[9] !== b) { + t7 = [b]; + $[9] = b; + $[10] = t7; + } else { + t7 = $[10]; + } + let t8; + if ($[11] !== t7 || $[12] !== item2) { + t8 = ; + $[11] = t7; + $[12] = item2; + $[13] = t8; + } else { + t8 = $[13]; + } + let t9; + if ($[14] !== t6 || $[15] !== t8) { + t9 = ( + <> + {t6} + {t8} + + ); + $[14] = t6; + $[15] = t8; + $[16] = t9; + } else { + t9 = $[16]; + } + return t9; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 0, b: 0 }], + sequentialRenders: [ + { a: 0, b: 0 }, + { a: 1, b: 0 }, + { a: 1, b: 1 }, + { a: 1, b: 2 }, + { a: 2, b: 2 }, + { a: 3, b: 2 }, + { a: 0, b: 0 }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[0],"output":{"b":0}}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[1],"output":{"b":1}}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[2],"output":{"b":2}}
+
{"inputs":[2],"output":{"a":2}}
{"inputs":[2],"output":{"b":2}}
+
{"inputs":[3],"output":{"a":3}}
{"inputs":[2],"output":{"b":2}}
+
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
+logs: [{ a: 0 },{ b: 0 },{ a: 1 },{ b: 0 },{ a: 1 },{ b: 1 },{ a: 1 },{ b: 2 },{ a: 2 },{ b: 2 },{ a: 3 },{ b: 2 },{ a: 0 },{ b: 0 }] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.tsx new file mode 100644 index 0000000000000..ec5dcf41e004c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.tsx @@ -0,0 +1,30 @@ +import {useMemo} from 'react'; +import {ValidateMemoization} from 'shared-runtime'; +import typedLog from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + typedLog(item1, item2); + + return ( + <> + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md new file mode 100644 index 0000000000000..072c6d03d9adb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md @@ -0,0 +1,145 @@ + +## Input + +```javascript +import {useMemo} from 'react'; +import {typedLog, ValidateMemoization} from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + typedLog(item1, item2); + + return ( + <> + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useMemo } from "react"; +import { typedLog, ValidateMemoization } from "shared-runtime"; + +export function Component(t0) { + const $ = _c(17); + const { a, b } = t0; + let t1; + let t2; + if ($[0] !== a) { + t2 = { a }; + $[0] = a; + $[1] = t2; + } else { + t2 = $[1]; + } + t1 = t2; + const item1 = t1; + let t3; + let t4; + if ($[2] !== b) { + t4 = { b }; + $[2] = b; + $[3] = t4; + } else { + t4 = $[3]; + } + t3 = t4; + const item2 = t3; + typedLog(item1, item2); + let t5; + if ($[4] !== a) { + t5 = [a]; + $[4] = a; + $[5] = t5; + } else { + t5 = $[5]; + } + let t6; + if ($[6] !== t5 || $[7] !== item1) { + t6 = ; + $[6] = t5; + $[7] = item1; + $[8] = t6; + } else { + t6 = $[8]; + } + let t7; + if ($[9] !== b) { + t7 = [b]; + $[9] = b; + $[10] = t7; + } else { + t7 = $[10]; + } + let t8; + if ($[11] !== t7 || $[12] !== item2) { + t8 = ; + $[11] = t7; + $[12] = item2; + $[13] = t8; + } else { + t8 = $[13]; + } + let t9; + if ($[14] !== t6 || $[15] !== t8) { + t9 = ( + <> + {t6} + {t8} + + ); + $[14] = t6; + $[15] = t8; + $[16] = t9; + } else { + t9 = $[16]; + } + return t9; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 0, b: 0 }], + sequentialRenders: [ + { a: 0, b: 0 }, + { a: 1, b: 0 }, + { a: 1, b: 1 }, + { a: 1, b: 2 }, + { a: 2, b: 2 }, + { a: 3, b: 2 }, + { a: 0, b: 0 }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[0],"output":{"b":0}}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[1],"output":{"b":1}}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[2],"output":{"b":2}}
+
{"inputs":[2],"output":{"a":2}}
{"inputs":[2],"output":{"b":2}}
+
{"inputs":[3],"output":{"a":3}}
{"inputs":[2],"output":{"b":2}}
+
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
+logs: [{ a: 0 },{ b: 0 },{ a: 1 },{ b: 0 },{ a: 1 },{ b: 1 },{ a: 1 },{ b: 2 },{ a: 2 },{ b: 2 },{ a: 3 },{ b: 2 },{ a: 0 },{ b: 0 }] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.tsx new file mode 100644 index 0000000000000..5fb53d9ca85d4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.tsx @@ -0,0 +1,29 @@ +import {useMemo} from 'react'; +import {typedLog, ValidateMemoization} from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + typedLog(item1, item2); + + return ( + <> + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md new file mode 100644 index 0000000000000..caa74267f326b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md @@ -0,0 +1,185 @@ + +## Input + +```javascript +import {useMemo} from 'react'; +import * as SharedRuntime from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + const items = useMemo(() => { + const items = []; + SharedRuntime.typedArrayPush(items, item1); + SharedRuntime.typedArrayPush(items, item2); + return items; + }, [item1, item2]); + + return ( + <> + + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useMemo } from "react"; +import * as SharedRuntime from "shared-runtime"; + +export function Component(t0) { + const $ = _c(27); + const { a, b } = t0; + let t1; + let t2; + if ($[0] !== a) { + t2 = { a }; + $[0] = a; + $[1] = t2; + } else { + t2 = $[1]; + } + t1 = t2; + const item1 = t1; + let t3; + let t4; + if ($[2] !== b) { + t4 = { b }; + $[2] = b; + $[3] = t4; + } else { + t4 = $[3]; + } + t3 = t4; + const item2 = t3; + let t5; + let items; + if ($[4] !== item1 || $[5] !== item2) { + items = []; + SharedRuntime.typedArrayPush(items, item1); + SharedRuntime.typedArrayPush(items, item2); + $[4] = item1; + $[5] = item2; + $[6] = items; + } else { + items = $[6]; + } + t5 = items; + const items_0 = t5; + let t6; + if ($[7] !== a) { + t6 = [a]; + $[7] = a; + $[8] = t6; + } else { + t6 = $[8]; + } + const t7 = items_0[0]; + let t8; + if ($[9] !== t6 || $[10] !== t7) { + t8 = ; + $[9] = t6; + $[10] = t7; + $[11] = t8; + } else { + t8 = $[11]; + } + let t9; + if ($[12] !== b) { + t9 = [b]; + $[12] = b; + $[13] = t9; + } else { + t9 = $[13]; + } + const t10 = items_0[1]; + let t11; + if ($[14] !== t9 || $[15] !== t10) { + t11 = ; + $[14] = t9; + $[15] = t10; + $[16] = t11; + } else { + t11 = $[16]; + } + let t12; + if ($[17] !== a || $[18] !== b) { + t12 = [a, b]; + $[17] = a; + $[18] = b; + $[19] = t12; + } else { + t12 = $[19]; + } + let t13; + if ($[20] !== t12 || $[21] !== items_0) { + t13 = ; + $[20] = t12; + $[21] = items_0; + $[22] = t13; + } else { + t13 = $[22]; + } + let t14; + if ($[23] !== t8 || $[24] !== t11 || $[25] !== t13) { + t14 = ( + <> + {t8} + {t11} + {t13} + + ); + $[23] = t8; + $[24] = t11; + $[25] = t13; + $[26] = t14; + } else { + t14 = $[26]; + } + return t14; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 0, b: 0 }], + sequentialRenders: [ + { a: 0, b: 0 }, + { a: 1, b: 0 }, + { a: 1, b: 1 }, + { a: 1, b: 2 }, + { a: 2, b: 2 }, + { a: 3, b: 2 }, + { a: 0, b: 0 }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
{"inputs":[0,0],"output":[{"a":0},{"b":0}]}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[0],"output":{"b":0}}
{"inputs":[1,0],"output":[{"a":1},{"b":0}]}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[1],"output":{"b":1}}
{"inputs":[1,1],"output":[{"a":1},{"b":1}]}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[2],"output":{"b":2}}
{"inputs":[1,2],"output":[{"a":1},{"b":2}]}
+
{"inputs":[2],"output":{"a":2}}
{"inputs":[2],"output":{"b":2}}
{"inputs":[2,2],"output":[{"a":2},{"b":2}]}
+
{"inputs":[3],"output":{"a":3}}
{"inputs":[2],"output":{"b":2}}
{"inputs":[3,2],"output":[{"a":3},{"b":2}]}
+
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
{"inputs":[0,0],"output":[{"a":0},{"b":0}]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.tsx new file mode 100644 index 0000000000000..6479df9a5a86e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.tsx @@ -0,0 +1,35 @@ +import {useMemo} from 'react'; +import * as SharedRuntime from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + const items = useMemo(() => { + const items = []; + SharedRuntime.typedArrayPush(items, item1); + SharedRuntime.typedArrayPush(items, item2); + return items; + }, [item1, item2]); + + return ( + <> + + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md new file mode 100644 index 0000000000000..a92abd4ca597c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md @@ -0,0 +1,185 @@ + +## Input + +```javascript +import {useMemo} from 'react'; +import {typedArrayPush, ValidateMemoization} from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + const items = useMemo(() => { + const items = []; + typedArrayPush(items, item1); + typedArrayPush(items, item2); + return items; + }, [item1, item2]); + + return ( + <> + + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useMemo } from "react"; +import { typedArrayPush, ValidateMemoization } from "shared-runtime"; + +export function Component(t0) { + const $ = _c(27); + const { a, b } = t0; + let t1; + let t2; + if ($[0] !== a) { + t2 = { a }; + $[0] = a; + $[1] = t2; + } else { + t2 = $[1]; + } + t1 = t2; + const item1 = t1; + let t3; + let t4; + if ($[2] !== b) { + t4 = { b }; + $[2] = b; + $[3] = t4; + } else { + t4 = $[3]; + } + t3 = t4; + const item2 = t3; + let t5; + let items; + if ($[4] !== item1 || $[5] !== item2) { + items = []; + typedArrayPush(items, item1); + typedArrayPush(items, item2); + $[4] = item1; + $[5] = item2; + $[6] = items; + } else { + items = $[6]; + } + t5 = items; + const items_0 = t5; + let t6; + if ($[7] !== a) { + t6 = [a]; + $[7] = a; + $[8] = t6; + } else { + t6 = $[8]; + } + const t7 = items_0[0]; + let t8; + if ($[9] !== t6 || $[10] !== t7) { + t8 = ; + $[9] = t6; + $[10] = t7; + $[11] = t8; + } else { + t8 = $[11]; + } + let t9; + if ($[12] !== b) { + t9 = [b]; + $[12] = b; + $[13] = t9; + } else { + t9 = $[13]; + } + const t10 = items_0[1]; + let t11; + if ($[14] !== t9 || $[15] !== t10) { + t11 = ; + $[14] = t9; + $[15] = t10; + $[16] = t11; + } else { + t11 = $[16]; + } + let t12; + if ($[17] !== a || $[18] !== b) { + t12 = [a, b]; + $[17] = a; + $[18] = b; + $[19] = t12; + } else { + t12 = $[19]; + } + let t13; + if ($[20] !== t12 || $[21] !== items_0) { + t13 = ; + $[20] = t12; + $[21] = items_0; + $[22] = t13; + } else { + t13 = $[22]; + } + let t14; + if ($[23] !== t8 || $[24] !== t11 || $[25] !== t13) { + t14 = ( + <> + {t8} + {t11} + {t13} + + ); + $[23] = t8; + $[24] = t11; + $[25] = t13; + $[26] = t14; + } else { + t14 = $[26]; + } + return t14; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 0, b: 0 }], + sequentialRenders: [ + { a: 0, b: 0 }, + { a: 1, b: 0 }, + { a: 1, b: 1 }, + { a: 1, b: 2 }, + { a: 2, b: 2 }, + { a: 3, b: 2 }, + { a: 0, b: 0 }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
{"inputs":[0,0],"output":[{"a":0},{"b":0}]}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[0],"output":{"b":0}}
{"inputs":[1,0],"output":[{"a":1},{"b":0}]}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[1],"output":{"b":1}}
{"inputs":[1,1],"output":[{"a":1},{"b":1}]}
+
{"inputs":[1],"output":{"a":1}}
{"inputs":[2],"output":{"b":2}}
{"inputs":[1,2],"output":[{"a":1},{"b":2}]}
+
{"inputs":[2],"output":{"a":2}}
{"inputs":[2],"output":{"b":2}}
{"inputs":[2,2],"output":[{"a":2},{"b":2}]}
+
{"inputs":[3],"output":{"a":3}}
{"inputs":[2],"output":{"b":2}}
{"inputs":[3,2],"output":[{"a":3},{"b":2}]}
+
{"inputs":[0],"output":{"a":0}}
{"inputs":[0],"output":{"b":0}}
{"inputs":[0,0],"output":[{"a":0},{"b":0}]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.tsx new file mode 100644 index 0000000000000..3afef5439bec3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.tsx @@ -0,0 +1,35 @@ +import {useMemo} from 'react'; +import {typedArrayPush, ValidateMemoization} from 'shared-runtime'; + +export function Component({a, b}) { + const item1 = useMemo(() => ({a}), [a]); + const item2 = useMemo(() => ({b}), [b]); + const items = useMemo(() => { + const items = []; + typedArrayPush(items, item1); + typedArrayPush(items, item2); + return items; + }, [item1, item2]); + + return ( + <> + + + + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: 0, b: 0}], + sequentialRenders: [ + {a: 0, b: 0}, + {a: 1, b: 0}, + {a: 1, b: 1}, + {a: 1, b: 2}, + {a: 2, b: 2}, + {a: 3, b: 2}, + {a: 0, b: 0}, + ], +}; diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index de0184f0bddb1..417a657d28012 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -31,6 +31,7 @@ import path from 'path'; import prettier from 'prettier'; import SproutTodoFilter from './SproutTodoFilter'; import {isExpectError} from './fixture-utils'; +import {makeSharedRuntimeTypeProvider} from './sprout/shared-runtime-type-provider'; export function parseLanguage(source: string): 'flow' | 'typescript' { return source.indexOf('@flow') !== -1 ? 'flow' : 'typescript'; } @@ -38,6 +39,8 @@ export function parseLanguage(source: string): 'flow' | 'typescript' { function makePluginOptions( firstLine: string, parseConfigPragmaFn: typeof ParseConfigPragma, + EffectEnum: typeof Effect, + ValueKindEnum: typeof ValueKind, ): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] { let gating = null; let enableEmitInstrumentForget = null; @@ -212,35 +215,10 @@ function makePluginOptions( const options = { environment: { ...config, - customHooks: new Map([ - [ - 'useFreeze', - { - valueKind: 'frozen' as ValueKind, - effectKind: 'freeze' as Effect, - transitiveMixedData: false, - noAlias: false, - }, - ], - [ - 'useFragment', - { - valueKind: 'frozen' as ValueKind, - effectKind: 'freeze' as Effect, - transitiveMixedData: true, - noAlias: true, - }, - ], - [ - 'useNoAlias', - { - valueKind: 'mutable' as ValueKind, - effectKind: 'read' as Effect, - transitiveMixedData: false, - noAlias: true, - }, - ], - ]), + moduleTypeProvider: makeSharedRuntimeTypeProvider({ + EffectEnum, + ValueKindEnum, + }), customMacros, enableEmitFreeze, enableEmitInstrumentForget, @@ -383,6 +361,8 @@ export async function transformFixtureInput( parseConfigPragmaFn: typeof ParseConfigPragma, plugin: BabelCore.PluginObj, includeEvaluator: boolean, + EffectEnum: typeof Effect, + ValueKindEnum: typeof ValueKind, ): Promise<{kind: 'ok'; value: TransformResult} | {kind: 'err'; msg: string}> { // Extract the first line to quickly check for custom test directives const firstLine = input.substring(0, input.indexOf('\n')); @@ -405,7 +385,12 @@ export async function transformFixtureInput( /** * Get Forget compiled code */ - const [options, logs] = makePluginOptions(firstLine, parseConfigPragmaFn); + const [options, logs] = makePluginOptions( + firstLine, + parseConfigPragmaFn, + EffectEnum, + ValueKindEnum, + ); const forgetResult = transformFromAstSync(inputAst, input, { filename: virtualFilepath, highlightCode: false, diff --git a/compiler/packages/snap/src/constants.ts b/compiler/packages/snap/src/constants.ts index bcc0b0ff1ca03..abee06c55be8a 100644 --- a/compiler/packages/snap/src/constants.ts +++ b/compiler/packages/snap/src/constants.ts @@ -17,6 +17,7 @@ export const COMPILER_PATH = path.join( 'Babel', 'BabelPlugin.js', ); +export const COMPILER_INDEX_PATH = path.join(process.cwd(), 'dist', 'index'); export const LOGGER_PATH = path.join( process.cwd(), 'dist', diff --git a/compiler/packages/snap/src/runner-worker.ts b/compiler/packages/snap/src/runner-worker.ts index 55c85b9466925..9447b2cddc52c 100644 --- a/compiler/packages/snap/src/runner-worker.ts +++ b/compiler/packages/snap/src/runner-worker.ts @@ -11,6 +11,7 @@ import type {parseConfigPragma as ParseConfigPragma} from 'babel-plugin-react-co import {TransformResult, transformFixtureInput} from './compiler'; import { COMPILER_PATH, + COMPILER_INDEX_PATH, LOGGER_PATH, PARSE_CONFIG_PRAGMA_PATH, } from './constants'; @@ -60,6 +61,9 @@ async function compile( const {default: BabelPluginReactCompiler} = require(COMPILER_PATH) as { default: PluginObj; }; + const {Effect: EffectEnum, ValueKind: ValueKindEnum} = require( + COMPILER_INDEX_PATH, + ); const {toggleLogging} = require(LOGGER_PATH); const {parseConfigPragma} = require(PARSE_CONFIG_PRAGMA_PATH) as { parseConfigPragma: typeof ParseConfigPragma; @@ -74,6 +78,8 @@ async function compile( parseConfigPragma, BabelPluginReactCompiler, includeEvaluator, + EffectEnum, + ValueKindEnum, ); if (result.kind === 'err') { diff --git a/compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts b/compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts new file mode 100644 index 0000000000000..fb0877d11474f --- /dev/null +++ b/compiler/packages/snap/src/sprout/shared-runtime-type-provider.ts @@ -0,0 +1,69 @@ +/** + * 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 type {Effect, ValueKind} from 'babel-plugin-react-compiler/src'; +import type {TypeConfig} from 'babel-plugin-react-compiler/src/HIR/TypeSchema'; + +export function makeSharedRuntimeTypeProvider({ + EffectEnum, + ValueKindEnum, +}: { + EffectEnum: typeof Effect; + ValueKindEnum: typeof ValueKind; +}) { + return function sharedRuntimeTypeProvider( + moduleName: string, + ): TypeConfig | null { + if (moduleName !== 'shared-runtime') { + return null; + } + return { + kind: 'object', + properties: { + default: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [], + restParam: EffectEnum.Read, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + typedArrayPush: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [EffectEnum.Store, EffectEnum.Capture], + restParam: EffectEnum.Capture, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + typedLog: { + kind: 'function', + calleeEffect: EffectEnum.Read, + positionalParams: [], + restParam: EffectEnum.Read, + returnType: {kind: 'type', name: 'Primitive'}, + returnValueKind: ValueKindEnum.Primitive, + }, + useFreeze: { + kind: 'hook', + returnType: {kind: 'type', name: 'Any'}, + }, + useFragment: { + kind: 'hook', + returnType: {kind: 'type', name: 'MixedReadonly'}, + noAlias: true, + }, + useNoAlias: { + kind: 'hook', + returnType: {kind: 'type', name: 'Any'}, + returnValueKind: ValueKindEnum.Mutable, + noAlias: true, + }, + }, + }; + }; +} diff --git a/compiler/packages/snap/src/sprout/shared-runtime.ts b/compiler/packages/snap/src/sprout/shared-runtime.ts index f15aaaaa4a2e5..bb1c65a6574ac 100644 --- a/compiler/packages/snap/src/sprout/shared-runtime.ts +++ b/compiler/packages/snap/src/sprout/shared-runtime.ts @@ -347,3 +347,12 @@ export function useFragment(..._args: Array): object { b: {c: {d: 4}}, }; } + +export function typedArrayPush(array: Array, item: T): void { + array.push(item); +} + +export function typedLog(...values: Array): void { + console.log(...values); +} +export default typedLog; From 8a20fc3b19b600a3b8666203f1877230c62becf9 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 21 Aug 2024 17:31:47 -0700 Subject: [PATCH 039/426] [compiler] Repro of missing memoization due to capturing w/o mutation If you have a function expression which _captures_ a mutable value (but does not mutate it), and that function is invoked during render, we infer the invocation as a mutation of the captured value. But in some circumstances we can prove that the captured value cannot have been mutated, and could in theory avoid inferring a mutation. ghstack-source-id: 47664e48ce8c51a6edf4d714d1acd1ec4781df80 Pull Request resolved: https://github.com/facebook/react/pull/30783 --- ...ed-function-inferred-as-mutation.expect.md | 54 +++++++++++++++++++ ...n-invoked-function-inferred-as-mutation.js | 33 ++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md new file mode 100644 index 0000000000000..1eb9b98b09529 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md @@ -0,0 +1,54 @@ + +## Input + +```javascript +// @flow @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {logValue, useFragment, useHook, typedLog} from 'shared-runtime'; + +component Component() { + const data = useFragment(); + + const getIsEnabled = () => { + if (data != null) { + return true; + } else { + return false; + } + }; + + // We infer that getIsEnabled returns a mutable value, such that + // isEnabled is mutable + const isEnabled = useMemo(() => getIsEnabled(), [getIsEnabled]); + + // We then infer getLoggingData as capturing that mutable value, + // so any calls to this function are then inferred as extending + // the mutable range of isEnabled + const getLoggingData = () => { + return { + isEnabled, + }; + }; + + // The call here is then inferred as an indirect mutation of isEnabled + useHook(getLoggingData()); + + return
typedLog(getLoggingData())} />; +} + +``` + + +## Error + +``` + 16 | // We infer that getIsEnabled returns a mutable value, such that + 17 | // isEnabled is mutable +> 18 | const isEnabled = useMemo(() => getIsEnabled(), [getIsEnabled]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value was memoized in source but not in compilation output. (18:18) + 19 | + 20 | // We then infer getLoggingData as capturing that mutable value, + 21 | // so any calls to this function are then inferred as extending +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js new file mode 100644 index 0000000000000..02114e26530c5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js @@ -0,0 +1,33 @@ +// @flow @validatePreserveExistingMemoizationGuarantees +import {useMemo} from 'react'; +import {logValue, useFragment, useHook, typedLog} from 'shared-runtime'; + +component Component() { + const data = useFragment(); + + const getIsEnabled = () => { + if (data != null) { + return true; + } else { + return false; + } + }; + + // We infer that getIsEnabled returns a mutable value, such that + // isEnabled is mutable + const isEnabled = useMemo(() => getIsEnabled(), [getIsEnabled]); + + // We then infer getLoggingData as capturing that mutable value, + // so any calls to this function are then inferred as extending + // the mutable range of isEnabled + const getLoggingData = () => { + return { + isEnabled, + }; + }; + + // The call here is then inferred as an indirect mutation of isEnabled + useHook(getLoggingData()); + + return
typedLog(getLoggingData())} />; +} From 217a0efcd90ef04556e0256e0eff9313bdbbcaca Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 21 Aug 2024 18:21:27 -0700 Subject: [PATCH 040/426] [compiler] Add returnIdentifier to function expressions This gives us a place to store type information, used in follow-up PRs. ghstack-source-id: ee0bfa253f63c30ccaac083b9f1f72b76617f19c Pull Request resolved: https://github.com/facebook/react/pull/30784 --- .../packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts | 3 +++ compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts | 1 + .../src/Optimization/LowerContextAccess.ts | 2 ++ ...epro-named-function-with-shadowed-local-same-name.expect.md | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 20fac9d610a08..4fec81c91146f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -211,11 +211,14 @@ export function lower( null, ); + const returnIdentifier = builder.makeTemporary(func.node.loc ?? GeneratedSource); + return Ok({ id, params, fnType: parent == null ? env.fnType : 'Other', returnType: null, // TODO: extract the actual return type node if present + returnIdentifier, body: builder.build(), context, generator: func.node.generator === true, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index e56c002c513bd..8c8682aa8cc2b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -286,6 +286,7 @@ export type HIRFunction = { env: Environment; params: Array; returnType: t.FlowType | t.TSType | null; + returnIdentifier: Identifier; context: Array; effects: Array | null; body: HIR; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts index 8455a094f05e7..5a21104d1d201 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts @@ -238,6 +238,7 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { phis: new Set(), }; + const returnIdentifier = createTemporaryPlace(env, GeneratedSource).identifier; const fn: HIRFunction = { loc: GeneratedSource, id: null, @@ -245,6 +246,7 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { env, params: [obj], returnType: null, + returnIdentifier, context: [], effects: null, body: { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md index db3a192eaf604..51b0bfd506973 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md @@ -22,7 +22,7 @@ function Component(props) { 7 | return hasErrors; 8 | } > 9 | return hasErrors(); - | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$16 (9:9) + | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$17 (9:9) 10 | } 11 | ``` From 8410c8b959b8e20adc5577cb7211702cfba0f78f Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 21 Aug 2024 21:17:29 -0700 Subject: [PATCH 041/426] [compiler] Infer return types of function expressions Uses the returnIdentifier added in the previous PR to provide a stable identifier for which we can infer a return type for functions, then wires up the equations in InferTypes to infer the type. ghstack-source-id: 22c0a9ea096daa5f72821fca2a5ff5b199f65c8b Pull Request resolved: https://github.com/facebook/react/pull/30785 --- .../src/HIR/BuildHIR.ts | 4 +- .../src/HIR/PrintHIR.ts | 6 ++- .../src/Optimization/LowerContextAccess.ts | 7 +++- ...rgeReactiveScopesThatInvalidateTogether.ts | 20 +++++---- .../src/TypeInference/InferTypes.ts | 20 ++++++++- ...ed-function-inferred-as-mutation.expect.md | 2 +- ...n-invoked-function-inferred-as-mutation.js | 2 +- ...oisting-simple-const-declaration.expect.md | 11 +++-- .../hoisting-simple-let-declaration.expect.md | 11 +++-- ...invoked-callback-escaping-return.expect.md | 41 ++++++++----------- 10 files changed, 74 insertions(+), 50 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 4fec81c91146f..cf2c113d8c418 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -211,7 +211,9 @@ export function lower( null, ); - const returnIdentifier = builder.makeTemporary(func.node.loc ?? GeneratedSource); + const returnIdentifier = builder.makeTemporary( + func.node.loc ?? GeneratedSource, + ); return Ok({ id, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index 59f067787359f..19a3a718285f4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -72,6 +72,7 @@ export function printFunction(fn: HIRFunction): string { if (definition.length !== 0) { output.push(definition); } + output.push(printType(fn.returnIdentifier.type)); output.push(printHIR(fn.body)); output.push(...fn.directives); return output.join('\n'); @@ -555,7 +556,10 @@ export function printInstructionValue(instrValue: ReactiveValue): string { } }) .join(', ') ?? ''; - value = `${kind} ${name} @deps[${deps}] @context[${context}] @effects[${effects}]:\n${fn}`; + const type = printType( + instrValue.loweredFunc.func.returnIdentifier.type, + ).trim(); + value = `${kind} ${name} @deps[${deps}] @context[${context}] @effects[${effects}]${type !== '' ? ` return${type}` : ''}:\n${fn}`; break; } case 'TaggedTemplateExpression': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts index 5a21104d1d201..5c6d19a0f2cfa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts @@ -238,7 +238,10 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { phis: new Set(), }; - const returnIdentifier = createTemporaryPlace(env, GeneratedSource).identifier; + const returnIdentifier = createTemporaryPlace( + env, + GeneratedSource, + ).identifier; const fn: HIRFunction = { loc: GeneratedSource, id: null, @@ -246,7 +249,7 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { env, params: [obj], returnType: null, - returnIdentifier, + returnIdentifier, context: [], effects: null, body: { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts index 2c9004e6ad9a6..1e73697783f0b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts @@ -481,14 +481,20 @@ function canMergeScopes( } function isAlwaysInvalidatingType(type: Type): boolean { - if (type.kind === 'Object') { - switch (type.shapeId) { - case BuiltInArrayId: - case BuiltInObjectId: - case BuiltInFunctionId: - case BuiltInJsxId: { - return true; + switch (type.kind) { + case 'Object': { + switch (type.shapeId) { + case BuiltInArrayId: + case BuiltInObjectId: + case BuiltInFunctionId: + case BuiltInJsxId: { + return true; + } } + break; + } + case 'Function': { + return true; } } return false; diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index 4dfeb676a3d0b..a8859f129bcfc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -88,6 +88,7 @@ function apply(func: HIRFunction, unifier: Unifier): void { } } } + func.returnIdentifier.type = unifier.get(func.returnIdentifier.type); } type TypeEquation = { @@ -122,6 +123,7 @@ function* generate( } const names = new Map(); + const returnTypes: Array = []; for (const [_, block] of func.body.blocks) { for (const phi of block.phis) { yield equation(phi.type, { @@ -133,6 +135,18 @@ function* generate( for (const instr of block.instructions) { yield* generateInstructionTypes(func.env, names, instr); } + const terminal = block.terminal; + if (terminal.kind === 'return') { + returnTypes.push(terminal.value.identifier.type); + } + } + if (returnTypes.length > 1) { + yield equation(func.returnIdentifier.type, { + kind: 'Phi', + operands: returnTypes, + }); + } else if (returnTypes.length === 1) { + yield equation(func.returnIdentifier.type, returnTypes[0]!); } } @@ -346,7 +360,11 @@ function* generateInstructionTypes( case 'FunctionExpression': { yield* generate(value.loweredFunc.func); - yield equation(left, {kind: 'Object', shapeId: BuiltInFunctionId}); + yield equation(left, { + kind: 'Function', + shapeId: BuiltInFunctionId, + return: value.loweredFunc.func.returnIdentifier.type, + }); break; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md index 1eb9b98b09529..5205445751249 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md @@ -13,7 +13,7 @@ component Component() { if (data != null) { return true; } else { - return false; + return {}; } }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js index 02114e26530c5..1621ab41c9050 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js @@ -9,7 +9,7 @@ component Component() { if (data != null) { return true; } else { - return false; + return {}; } }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md index ae5bf41e3227c..7939c9143d1d7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md @@ -25,18 +25,17 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function hoisting() { const $ = _c(1); - let t0; + let foo; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const foo = () => bar + baz; + foo = () => bar + baz; const bar = 3; const baz = 2; - t0 = foo(); - $[0] = t0; + $[0] = foo; } else { - t0 = $[0]; + foo = $[0]; } - return t0; + return foo(); } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md index 8974664b0515f..8d694a984aed5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md @@ -25,18 +25,17 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function hoisting() { const $ = _c(1); - let t0; + let foo; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const foo = () => bar + baz; + foo = () => bar + baz; let bar = 3; let baz = 2; - t0 = foo(); - $[0] = t0; + $[0] = foo; } else { - t0 = $[0]; + foo = $[0]; } - return t0; + return foo(); } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md index 14913665c5474..6d9183915467f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md @@ -40,7 +40,7 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe import { useCallback } from "react"; function Component(t0) { - const $ = _c(11); + const $ = _c(9); const { entity, children } = t0; let t1; if ($[0] !== entity) { @@ -51,46 +51,39 @@ function Component(t0) { t1 = $[1]; } const showMessage = t1; + + const shouldShowMessage = showMessage(); let t2; - if ($[2] !== showMessage) { - t2 = showMessage(); - $[2] = showMessage; + if ($[2] !== shouldShowMessage) { + t2 =
{shouldShowMessage}
; + $[2] = shouldShowMessage; $[3] = t2; } else { t2 = $[3]; } - const shouldShowMessage = t2; let t3; - if ($[4] !== shouldShowMessage) { - t3 =
{shouldShowMessage}
; - $[4] = shouldShowMessage; + if ($[4] !== children) { + t3 =
{children}
; + $[4] = children; $[5] = t3; } else { t3 = $[5]; } let t4; - if ($[6] !== children) { - t4 =
{children}
; - $[6] = children; - $[7] = t4; - } else { - t4 = $[7]; - } - let t5; - if ($[8] !== t3 || $[9] !== t4) { - t5 = ( + if ($[6] !== t2 || $[7] !== t3) { + t4 = (
+ {t2} {t3} - {t4}
); - $[8] = t3; - $[9] = t4; - $[10] = t5; + $[6] = t2; + $[7] = t3; + $[8] = t4; } else { - t5 = $[10]; + t4 = $[8]; } - return t5; + return t4; } export const FIXTURE_ENTRYPOINT = { From 98b57408216c80ec75723773524466657b4956b6 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Thu, 22 Aug 2024 09:06:58 -0700 Subject: [PATCH 042/426] [compiler] Rename HIRFunction.returnType Rename this field so we can use it for the actual return type. ghstack-source-id: 118d7dcfbbcc40911bf6d13f14e70053e436738d Pull Request resolved: https://github.com/facebook/react/pull/30789 --- .../packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts | 2 +- compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts | 2 +- .../src/Optimization/LowerContextAccess.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index cf2c113d8c418..1b0d9f455900d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -219,7 +219,7 @@ export function lower( id, params, fnType: parent == null ? env.fnType : 'Other', - returnType: null, // TODO: extract the actual return type node if present + returnTypeAnnotation: null, // TODO: extract the actual return type node if present returnIdentifier, body: builder.build(), context, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 8c8682aa8cc2b..1b866bb4c38a7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -285,7 +285,7 @@ export type HIRFunction = { fnType: ReactFunctionType; env: Environment; params: Array; - returnType: t.FlowType | t.TSType | null; + returnTypeAnnotation: t.FlowType | t.TSType | null; returnIdentifier: Identifier; context: Array; effects: Array | null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts index 5c6d19a0f2cfa..7ae39d695ad53 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts @@ -248,7 +248,7 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { fnType: 'Other', env, params: [obj], - returnType: null, + returnTypeAnnotation: null, returnIdentifier, context: [], effects: null, From 7a3fcc9898d57a723613814bd19ec1d60805e5c8 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Thu, 22 Aug 2024 09:07:01 -0700 Subject: [PATCH 043/426] [compiler] Flatten returnIdentifier to just returnType We don't a full Identifier object for the return type, we can just store the type. ghstack-source-id: 4594d64ce3900ced3e461945697926489898318e Pull Request resolved: https://github.com/facebook/react/pull/30790 --- .../babel-plugin-react-compiler/src/HIR/BuildHIR.ts | 6 +----- .../packages/babel-plugin-react-compiler/src/HIR/HIR.ts | 2 +- .../babel-plugin-react-compiler/src/HIR/PrintHIR.ts | 6 ++---- .../src/Optimization/LowerContextAccess.ts | 7 ++----- .../src/TypeInference/InferTypes.ts | 8 ++++---- ...named-function-with-shadowed-local-same-name.expect.md | 2 +- 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 1b0d9f455900d..06fcfbea7ecc0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -211,16 +211,12 @@ export function lower( null, ); - const returnIdentifier = builder.makeTemporary( - func.node.loc ?? GeneratedSource, - ); - return Ok({ id, params, fnType: parent == null ? env.fnType : 'Other', returnTypeAnnotation: null, // TODO: extract the actual return type node if present - returnIdentifier, + returnType: makeType(), body: builder.build(), context, generator: func.node.generator === true, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 1b866bb4c38a7..ea121c6fcd727 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -286,7 +286,7 @@ export type HIRFunction = { env: Environment; params: Array; returnTypeAnnotation: t.FlowType | t.TSType | null; - returnIdentifier: Identifier; + returnType: Type; context: Array; effects: Array | null; body: HIR; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index 19a3a718285f4..a5ad303d7a587 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -72,7 +72,7 @@ export function printFunction(fn: HIRFunction): string { if (definition.length !== 0) { output.push(definition); } - output.push(printType(fn.returnIdentifier.type)); + output.push(printType(fn.returnType)); output.push(printHIR(fn.body)); output.push(...fn.directives); return output.join('\n'); @@ -556,9 +556,7 @@ export function printInstructionValue(instrValue: ReactiveValue): string { } }) .join(', ') ?? ''; - const type = printType( - instrValue.loweredFunc.func.returnIdentifier.type, - ).trim(); + const type = printType(instrValue.loweredFunc.func.returnType).trim(); value = `${kind} ${name} @deps[${deps}] @context[${context}] @effects[${effects}]${type !== '' ? ` return${type}` : ''}:\n${fn}`; break; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts index 7ae39d695ad53..e27b8f952148a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/LowerContextAccess.ts @@ -23,6 +23,7 @@ import { isUseContextHookType, makeBlockId, makeInstructionId, + makeType, markInstructionIds, promoteTemporary, reversePostorderBlocks, @@ -238,10 +239,6 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { phis: new Set(), }; - const returnIdentifier = createTemporaryPlace( - env, - GeneratedSource, - ).identifier; const fn: HIRFunction = { loc: GeneratedSource, id: null, @@ -249,7 +246,7 @@ function emitSelectorFn(env: Environment, keys: Array): Instruction { env, params: [obj], returnTypeAnnotation: null, - returnIdentifier, + returnType: makeType(), context: [], effects: null, body: { diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index a8859f129bcfc..d0d23f0823df8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -88,7 +88,7 @@ function apply(func: HIRFunction, unifier: Unifier): void { } } } - func.returnIdentifier.type = unifier.get(func.returnIdentifier.type); + func.returnType = unifier.get(func.returnType); } type TypeEquation = { @@ -141,12 +141,12 @@ function* generate( } } if (returnTypes.length > 1) { - yield equation(func.returnIdentifier.type, { + yield equation(func.returnType, { kind: 'Phi', operands: returnTypes, }); } else if (returnTypes.length === 1) { - yield equation(func.returnIdentifier.type, returnTypes[0]!); + yield equation(func.returnType, returnTypes[0]!); } } @@ -363,7 +363,7 @@ function* generateInstructionTypes( yield equation(left, { kind: 'Function', shapeId: BuiltInFunctionId, - return: value.loweredFunc.func.returnIdentifier.type, + return: value.loweredFunc.func.returnType, }); break; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md index 51b0bfd506973..db3a192eaf604 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-named-function-with-shadowed-local-same-name.expect.md @@ -22,7 +22,7 @@ function Component(props) { 7 | return hasErrors; 8 | } > 9 | return hasErrors(); - | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$17 (9:9) + | ^^^^^^^^^ Invariant: [hoisting] Expected value for identifier to be initialized. hasErrors_0$16 (9:9) 10 | } 11 | ``` From e483df4658473ca9c917a42be4869d445be00807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 22 Aug 2024 12:34:48 -0400 Subject: [PATCH 044/426] [Flight ESM] Wire up Source Maps in the flight-esm fixture (#30758) Same as #29708 but for the flight-esm fixture. --- fixtures/flight-esm/server/global.js | 39 +++++++++++++ fixtures/flight-esm/server/region.js | 84 ++++++++++++++++++++++++++++ fixtures/flight-esm/src/index.js | 11 ++++ fixtures/flight/src/index.js | 21 ++++--- 4 files changed, 147 insertions(+), 8 deletions(-) diff --git a/fixtures/flight-esm/server/global.js b/fixtures/flight-esm/server/global.js index 1088d42967a2f..c0b148fc063c4 100644 --- a/fixtures/flight-esm/server/global.js +++ b/fixtures/flight-esm/server/global.js @@ -131,6 +131,45 @@ app.use( express.static('node_modules/react-server-dom-esm/esm') ); +if (process.env.NODE_ENV === 'development') { + app.get('/source-maps', async function (req, res, next) { + // Proxy the request to the regional server. + const proxiedHeaders = { + 'X-Forwarded-Host': req.hostname, + 'X-Forwarded-For': req.ips, + 'X-Forwarded-Port': 3000, + 'X-Forwarded-Proto': req.protocol, + }; + + const promiseForData = request( + { + host: '127.0.0.1', + port: 3001, + method: req.method, + path: req.originalUrl, + headers: proxiedHeaders, + }, + req + ); + + try { + const rscResponse = await promiseForData; + res.set('Content-type', 'application/json'); + rscResponse.on('data', data => { + res.write(data); + res.flush(); + }); + rscResponse.on('end', data => { + res.end(); + }); + } catch (e) { + console.error(`Failed to proxy request: ${e.stack}`); + res.statusCode = 500; + res.end(); + } + }); +} + app.listen(3000, () => { console.log('Global Fizz/Webpack Server listening on port 3000...'); }); diff --git a/fixtures/flight-esm/server/region.js b/fixtures/flight-esm/server/region.js index c7e8d9aad33cc..fe992b6daf538 100644 --- a/fixtures/flight-esm/server/region.js +++ b/fixtures/flight-esm/server/region.js @@ -17,6 +17,8 @@ const app = express(); const compress = require('compression'); const {Readable} = require('node:stream'); +const nodeModule = require('node:module'); + app.use(compress()); // Application @@ -116,6 +118,88 @@ app.get('/todos', function (req, res) { ]); }); +if (process.env.NODE_ENV === 'development') { + const rootDir = path.resolve(__dirname, '../'); + + app.get('/source-maps', async function (req, res, next) { + try { + res.set('Content-type', 'application/json'); + let requestedFilePath = req.query.name; + + let isCompiledOutput = false; + if (requestedFilePath.startsWith('file://')) { + // We assume that if it was prefixed with file:// it's referring to the compiled output + // and if it's a direct file path we assume it's source mapped back to original format. + isCompiledOutput = true; + requestedFilePath = url.fileURLToPath(requestedFilePath); + } + + const relativePath = path.relative(rootDir, requestedFilePath); + if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) { + // This is outside the root directory of the app. Forbid it to be served. + res.status = 403; + res.write('{}'); + res.end(); + return; + } + + const sourceMap = nodeModule.findSourceMap(requestedFilePath); + let map; + if (requestedFilePath.startsWith('node:')) { + // This is a node internal. We don't include any source code for this but we still + // generate a source map for it so that we can add it to an ignoreList automatically. + map = { + version: 3, + // We use the node:// protocol convention to teach Chrome DevTools that this is + // on a different protocol and not part of the current page. + sources: ['node:///' + requestedFilePath.slice(5)], + sourcesContent: ['// Node Internals'], + mappings: 'AAAA', + ignoreList: [0], + sourceRoot: '', + }; + } else if (!sourceMap || !isCompiledOutput) { + // If a file doesn't have a source map, such as this file, then we generate a blank + // source map that just contains the original content and segments pointing to the + // original lines. If a line number points to uncompiled output, like if source mapping + // was already applied we also use this path. + const sourceContent = await readFile(requestedFilePath, 'utf8'); + const lines = sourceContent.split('\n').length; + // We ensure to absolute + const sourceURL = url.pathToFileURL(requestedFilePath); + map = { + version: 3, + sources: [sourceURL], + sourcesContent: [sourceContent], + // Note: This approach to mapping each line only lets you jump to each line + // not jump to a column within a line. To do that, you need a proper source map + // generated for each parsed segment or add a segment for each column. + mappings: 'AAAA' + ';AACA'.repeat(lines - 1), + sourceRoot: '', + // Add any node_modules to the ignore list automatically. + ignoreList: requestedFilePath.includes('node_modules') + ? [0] + : undefined, + }; + } else { + // We always set prepareStackTrace before reading the stack so that we get the stack + // without source maps applied. Therefore we have to use the original source map. + // If something read .stack before we did, we might observe the line/column after + // source mapping back to the original file. We use the isCompiledOutput check above + // in that case. + map = sourceMap.payload; + } + res.write(JSON.stringify(map)); + res.end(); + } catch (x) { + res.status = 500; + res.write('{}'); + res.end(); + console.error(x); + } + }); +} + app.listen(3001, () => { console.log('Regional Flight Server listening on port 3001...'); }); diff --git a/fixtures/flight-esm/src/index.js b/fixtures/flight-esm/src/index.js index 30d060af6342c..6cef6c6c3c547 100644 --- a/fixtures/flight-esm/src/index.js +++ b/fixtures/flight-esm/src/index.js @@ -4,6 +4,15 @@ import ReactDOM from 'react-dom/client'; import {createFromFetch, encodeReply} from 'react-server-dom-esm/client'; const moduleBaseURL = '/src/'; + +function findSourceMapURL(fileName) { + return ( + document.location.origin + + '/source-maps?name=' + + encodeURIComponent(fileName) + ); +} + let updateRoot; async function callServer(id, args) { const response = fetch('/', { @@ -17,6 +26,7 @@ async function callServer(id, args) { const {returnValue, root} = await createFromFetch(response, { callServer, moduleBaseURL, + findSourceMapURL, }); // Refresh the tree with the new RSC payload. startTransition(() => { @@ -34,6 +44,7 @@ let data = createFromFetch( { callServer, moduleBaseURL, + findSourceMapURL, } ); diff --git a/fixtures/flight/src/index.js b/fixtures/flight/src/index.js index b4b538a3a9992..755551047535b 100644 --- a/fixtures/flight/src/index.js +++ b/fixtures/flight/src/index.js @@ -6,6 +6,14 @@ import {createFromFetch, encodeReply} from 'react-server-dom-webpack/client'; // TODO: This should be a dependency of the App but we haven't implemented CSS in Node yet. import './style.css'; +function findSourceMapURL(fileName) { + return ( + document.location.origin + + '/source-maps?name=' + + encodeURIComponent(fileName) + ); +} + let updateRoot; async function callServer(id, args) { const response = fetch('/', { @@ -16,7 +24,10 @@ async function callServer(id, args) { }, body: await encodeReply(args), }); - const {returnValue, root} = await createFromFetch(response, {callServer}); + const {returnValue, root} = await createFromFetch(response, { + callServer, + findSourceMapURL, + }); // Refresh the tree with the new RSC payload. startTransition(() => { updateRoot(root); @@ -39,13 +50,7 @@ async function hydrateApp() { }), { callServer, - findSourceMapURL(fileName) { - return ( - document.location.origin + - '/source-maps?name=' + - encodeURIComponent(fileName) - ); - }, + findSourceMapURL, } ); From 97e2ce6a003db070d1d14ca25ac4b30e1df4a8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 22 Aug 2024 12:35:16 -0400 Subject: [PATCH 045/426] [Flight] Enable Server Action Source Maps in flight-esm Fixture (#30763) Stacked on #30758 and #30755. This is copy paste from #30755 into the ESM package. We use the `webpack-sources` package for the source map utility but it's not actually dependent on Webpack itself. Could probably inline it in the build. --- fixtures/flight-esm/package.json | 5 +- fixtures/flight-esm/yarn.lock | 5 + packages/react-server-dom-esm/package.json | 3 +- .../src/ReactFlightESMNodeLoader.js | 403 ++++++++++++++++-- 4 files changed, 372 insertions(+), 44 deletions(-) diff --git a/fixtures/flight-esm/package.json b/fixtures/flight-esm/package.json index 8188df5abbd59..cb4ca1ea30b82 100644 --- a/fixtures/flight-esm/package.json +++ b/fixtures/flight-esm/package.json @@ -13,14 +13,15 @@ "prompts": "^2.4.2", "react": "experimental", "react-dom": "experimental", - "undici": "^5.20.0" + "undici": "^5.20.0", + "webpack-sources": "^3.2.0" }, "scripts": { "predev": "cp -r ../../build/oss-experimental/* ./node_modules/", "prestart": "cp -r ../../build/oss-experimental/* ./node_modules/", "dev": "concurrently \"npm run dev:region\" \"npm run dev:global\"", "dev:global": "NODE_ENV=development BUILD_PATH=dist node server/global", - "dev:region": "NODE_ENV=development BUILD_PATH=dist nodemon --watch src --watch dist -- --experimental-loader ./loader/region.js --conditions=react-server server/region", + "dev:region": "NODE_ENV=development BUILD_PATH=dist nodemon --watch src --watch dist -- --enable-source-maps --experimental-loader ./loader/region.js --conditions=react-server server/region", "start": "concurrently \"npm run start:region\" \"npm run start:global\"", "start:global": "NODE_ENV=production node server/global", "start:region": "NODE_ENV=production node --experimental-loader ./loader/region.js --conditions=react-server server/region" diff --git a/fixtures/flight-esm/yarn.lock b/fixtures/flight-esm/yarn.lock index 8d336e519453b..2eae2a7a934a6 100644 --- a/fixtures/flight-esm/yarn.lock +++ b/fixtures/flight-esm/yarn.lock @@ -755,6 +755,11 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +webpack-sources@^3.2.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" diff --git a/packages/react-server-dom-esm/package.json b/packages/react-server-dom-esm/package.json index a1f8f17f45014..a0cb32c34c9e8 100644 --- a/packages/react-server-dom-esm/package.json +++ b/packages/react-server-dom-esm/package.json @@ -58,6 +58,7 @@ "react-dom": "^19.0.0" }, "dependencies": { - "acorn-loose": "^8.3.0" + "acorn-loose": "^8.3.0", + "webpack-sources": "^3.2.0" } } diff --git a/packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js b/packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js index f54d5449fbbec..450f1b25d022a 100644 --- a/packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js +++ b/packages/react-server-dom-esm/src/ReactFlightESMNodeLoader.js @@ -9,6 +9,9 @@ import * as acorn from 'acorn-loose'; +import readMappings from 'webpack-sources/lib/helpers/readMappings.js'; +import createMappingsSerializer from 'webpack-sources/lib/helpers/createMappingsSerializer.js'; + type ResolveContext = { conditions: Array, parentURL: string | void, @@ -95,45 +98,102 @@ export async function getSource( return defaultGetSource(url, context, defaultGetSource); } -function addLocalExportedNames(names: Map, node: any) { +type ExportedEntry = { + localName: string, + exportedName: string, + type: null | string, + loc: { + start: {line: number, column: number}, + end: {line: number, column: number}, + }, + originalLine: number, + originalColumn: number, + originalSource: number, + nameIndex: number, +}; + +function addExportedEntry( + exportedEntries: Array, + localNames: Set, + localName: string, + exportedName: string, + type: null | 'function', + loc: { + start: {line: number, column: number}, + end: {line: number, column: number}, + }, +) { + if (localNames.has(localName)) { + // If the same local name is exported more than once, we only need one of the names. + return; + } + exportedEntries.push({ + localName, + exportedName, + type, + loc, + originalLine: -1, + originalColumn: -1, + originalSource: -1, + nameIndex: -1, + }); +} + +function addLocalExportedNames( + exportedEntries: Array, + localNames: Set, + node: any, +) { switch (node.type) { case 'Identifier': - names.set(node.name, node.name); + addExportedEntry( + exportedEntries, + localNames, + node.name, + node.name, + null, + node.loc, + ); return; case 'ObjectPattern': for (let i = 0; i < node.properties.length; i++) - addLocalExportedNames(names, node.properties[i]); + addLocalExportedNames(exportedEntries, localNames, node.properties[i]); return; case 'ArrayPattern': for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; - if (element) addLocalExportedNames(names, element); + if (element) + addLocalExportedNames(exportedEntries, localNames, element); } return; case 'Property': - addLocalExportedNames(names, node.value); + addLocalExportedNames(exportedEntries, localNames, node.value); return; case 'AssignmentPattern': - addLocalExportedNames(names, node.left); + addLocalExportedNames(exportedEntries, localNames, node.left); return; case 'RestElement': - addLocalExportedNames(names, node.argument); + addLocalExportedNames(exportedEntries, localNames, node.argument); return; case 'ParenthesizedExpression': - addLocalExportedNames(names, node.expression); + addLocalExportedNames(exportedEntries, localNames, node.expression); return; } } function transformServerModule( source: string, - body: any, + program: any, url: string, + sourceMap: any, loader: LoadFunction, ): string { - // If the same local name is exported more than once, we only need one of the names. - const localNames: Map = new Map(); - const localTypes: Map = new Map(); + const body = program.body; + + // This entry list needs to be in source location order. + const exportedEntries: Array = []; + // Dedupe set. + const localNames: Set = new Set(); for (let i = 0; i < body.length; i++) { const node = body[i]; @@ -143,11 +203,24 @@ function transformServerModule( break; case 'ExportDefaultDeclaration': if (node.declaration.type === 'Identifier') { - localNames.set(node.declaration.name, 'default'); + addExportedEntry( + exportedEntries, + localNames, + node.declaration.name, + 'default', + null, + node.declaration.loc, + ); } else if (node.declaration.type === 'FunctionDeclaration') { if (node.declaration.id) { - localNames.set(node.declaration.id.name, 'default'); - localTypes.set(node.declaration.id.name, 'function'); + addExportedEntry( + exportedEntries, + localNames, + node.declaration.id.name, + 'default', + 'function', + node.declaration.id.loc, + ); } else { // TODO: This needs to be rewritten inline because it doesn't have a local name. } @@ -158,41 +231,230 @@ function transformServerModule( if (node.declaration.type === 'VariableDeclaration') { const declarations = node.declaration.declarations; for (let j = 0; j < declarations.length; j++) { - addLocalExportedNames(localNames, declarations[j].id); + addLocalExportedNames( + exportedEntries, + localNames, + declarations[j].id, + ); } } else { const name = node.declaration.id.name; - localNames.set(name, name); - if (node.declaration.type === 'FunctionDeclaration') { - localTypes.set(name, 'function'); - } + addExportedEntry( + exportedEntries, + localNames, + name, + name, + + node.declaration.type === 'FunctionDeclaration' + ? 'function' + : null, + node.declaration.id.loc, + ); } } if (node.specifiers) { const specifiers = node.specifiers; for (let j = 0; j < specifiers.length; j++) { const specifier = specifiers[j]; - localNames.set(specifier.local.name, specifier.exported.name); + addExportedEntry( + exportedEntries, + localNames, + specifier.local.name, + specifier.exported.name, + null, + specifier.local.loc, + ); } } continue; } } - if (localNames.size === 0) { - return source; - } - let newSrc = source + '\n\n;'; - newSrc += - 'import {registerServerReference} from "react-server-dom-esm/server";\n'; - localNames.forEach(function (exported, local) { - if (localTypes.get(local) !== 'function') { - // We first check if the export is a function and if so annotate it. - newSrc += 'if (typeof ' + local + ' === "function") '; + + let mappings = + sourceMap && typeof sourceMap.mappings === 'string' + ? sourceMap.mappings + : ''; + let newSrc = source; + + if (exportedEntries.length > 0) { + let lastSourceIndex = 0; + let lastOriginalLine = 0; + let lastOriginalColumn = 0; + let lastNameIndex = 0; + let sourceLineCount = 0; + let lastMappedLine = 0; + + if (sourceMap) { + // We iterate source mapping entries and our matched exports in parallel to source map + // them to their original location. + let nextEntryIdx = 0; + let nextEntryLine = exportedEntries[nextEntryIdx].loc.start.line; + let nextEntryColumn = exportedEntries[nextEntryIdx].loc.start.column; + readMappings( + mappings, + ( + generatedLine: number, + generatedColumn: number, + sourceIndex: number, + originalLine: number, + originalColumn: number, + nameIndex: number, + ) => { + if ( + generatedLine > nextEntryLine || + (generatedLine === nextEntryLine && + generatedColumn > nextEntryColumn) + ) { + // We're past the entry which means that the best match we have is the previous entry. + if (lastMappedLine === nextEntryLine) { + // Match + exportedEntries[nextEntryIdx].originalLine = lastOriginalLine; + exportedEntries[nextEntryIdx].originalColumn = lastOriginalColumn; + exportedEntries[nextEntryIdx].originalSource = lastSourceIndex; + exportedEntries[nextEntryIdx].nameIndex = lastNameIndex; + } else { + // Skip if we didn't have any mappings on the exported line. + } + nextEntryIdx++; + if (nextEntryIdx < exportedEntries.length) { + nextEntryLine = exportedEntries[nextEntryIdx].loc.start.line; + nextEntryColumn = exportedEntries[nextEntryIdx].loc.start.column; + } else { + nextEntryLine = -1; + nextEntryColumn = -1; + } + } + lastMappedLine = generatedLine; + if (sourceIndex > -1) { + lastSourceIndex = sourceIndex; + } + if (originalLine > -1) { + lastOriginalLine = originalLine; + } + if (originalColumn > -1) { + lastOriginalColumn = originalColumn; + } + if (nameIndex > -1) { + lastNameIndex = nameIndex; + } + }, + ); + if (nextEntryIdx < exportedEntries.length) { + if (lastMappedLine === nextEntryLine) { + // Match + exportedEntries[nextEntryIdx].originalLine = lastOriginalLine; + exportedEntries[nextEntryIdx].originalColumn = lastOriginalColumn; + exportedEntries[nextEntryIdx].originalSource = lastSourceIndex; + exportedEntries[nextEntryIdx].nameIndex = lastNameIndex; + } + } + + for ( + let lastIdx = mappings.length - 1; + lastIdx >= 0 && mappings[lastIdx] === ';'; + lastIdx-- + ) { + // If the last mapped lines don't contain any segments, we don't get a callback from readMappings + // so we need to pad the number of mapped lines, with one for each empty line. + lastMappedLine++; + } + + sourceLineCount = program.loc.end.line; + if (sourceLineCount < lastMappedLine) { + throw new Error( + 'The source map has more mappings than there are lines.', + ); + } + // If the original source string had more lines than there are mappings in the source map. + // Add some extra padding of unmapped lines so that any lines that we add line up. + for ( + let extraLines = sourceLineCount - lastMappedLine; + extraLines > 0; + extraLines-- + ) { + mappings += ';'; + } + } else { + // If a file doesn't have a source map then we generate a blank source map that just + // contains the original content and segments pointing to the original lines. + sourceLineCount = 1; + let idx = -1; + while ((idx = source.indexOf('\n', idx + 1)) !== -1) { + sourceLineCount++; + } + mappings = 'AAAA' + ';AACA'.repeat(sourceLineCount - 1); + sourceMap = { + version: 3, + sources: [url], + sourcesContent: [source], + mappings: mappings, + sourceRoot: '', + }; + lastSourceIndex = 0; + lastOriginalLine = sourceLineCount; + lastOriginalColumn = 0; + lastNameIndex = -1; + lastMappedLine = sourceLineCount; + + for (let i = 0; i < exportedEntries.length; i++) { + // Point each entry to original location. + const entry = exportedEntries[i]; + entry.originalSource = 0; + entry.originalLine = entry.loc.start.line; + // We use column zero since we do the short-hand line-only source maps above. + entry.originalColumn = 0; // entry.loc.start.column; + } } - newSrc += 'registerServerReference(' + local + ','; - newSrc += JSON.stringify(url) + ','; - newSrc += JSON.stringify(exported) + ');\n'; - }); + + newSrc += '\n\n;'; + newSrc += + 'import {registerServerReference} from "react-server-dom-esm/server";\n'; + if (mappings) { + mappings += ';;'; + } + + const createMapping = createMappingsSerializer(); + + // Create an empty mapping pointing to where we last left off to reset the counters. + let generatedLine = 1; + createMapping( + generatedLine, + 0, + lastSourceIndex, + lastOriginalLine, + lastOriginalColumn, + lastNameIndex, + ); + for (let i = 0; i < exportedEntries.length; i++) { + const entry = exportedEntries[i]; + generatedLine++; + if (entry.type !== 'function') { + // We first check if the export is a function and if so annotate it. + newSrc += 'if (typeof ' + entry.localName + ' === "function") '; + } + newSrc += 'registerServerReference(' + entry.localName + ','; + newSrc += JSON.stringify(url) + ','; + newSrc += JSON.stringify(entry.exportedName) + ');\n'; + + mappings += createMapping( + generatedLine, + 0, + entry.originalSource, + entry.originalLine, + entry.originalColumn, + entry.nameIndex, + ); + } + } + + if (sourceMap) { + // Override with an new mappings and serialize an inline source map. + sourceMap.mappings = mappings; + newSrc += + '//# sourceMappingURL=data:application/json;charset=utf-8;base64,' + + Buffer.from(JSON.stringify(sourceMap)).toString('base64'); + } + return newSrc; } @@ -307,10 +569,13 @@ async function parseExportNamesInto( } async function transformClientModule( - body: any, + program: any, url: string, + sourceMap: any, loader: LoadFunction, ): Promise { + const body = program.body; + const names: Array = []; await parseExportNamesInto(body, names, url, loader); @@ -351,6 +616,9 @@ async function transformClientModule( newSrc += JSON.stringify(url) + ','; newSrc += JSON.stringify(name) + ');\n'; } + + // TODO: Generate source maps for Client Reference functions so they can point to their + // original locations. return newSrc; } @@ -391,12 +659,36 @@ async function transformModuleIfNeeded( return source; } - let body; + let sourceMappingURL = null; + let sourceMappingStart = 0; + let sourceMappingEnd = 0; + let sourceMappingLines = 0; + + let program; try { - body = acorn.parse(source, { + program = acorn.parse(source, { ecmaVersion: '2024', sourceType: 'module', - }).body; + locations: true, + onComment( + block: boolean, + text: string, + start: number, + end: number, + startLoc: {line: number, column: number}, + endLoc: {line: number, column: number}, + ) { + if ( + text.startsWith('# sourceMappingURL=') || + text.startsWith('@ sourceMappingURL=') + ) { + sourceMappingURL = text.slice(19); + sourceMappingStart = start; + sourceMappingEnd = end; + sourceMappingLines = endLoc.line - startLoc.line; + } + }, + }); } catch (x) { // eslint-disable-next-line react-internal/no-production-logging console.error('Error parsing %s %s', url, x.message); @@ -405,6 +697,8 @@ async function transformModuleIfNeeded( let useClient = false; let useServer = false; + + const body = program.body; for (let i = 0; i < body.length; i++) { const node = body[i]; if (node.type !== 'ExpressionStatement' || !node.directive) { @@ -428,11 +722,38 @@ async function transformModuleIfNeeded( ); } + let sourceMap = null; + if (sourceMappingURL) { + const sourceMapResult = await loader( + sourceMappingURL, + // $FlowFixMe + { + format: 'json', + conditions: [], + importAssertions: {type: 'json'}, + importAttributes: {type: 'json'}, + }, + loader, + ); + const sourceMapString = + typeof sourceMapResult.source === 'string' + ? sourceMapResult.source + : // $FlowFixMe + sourceMapResult.source.toString('utf8'); + sourceMap = JSON.parse(sourceMapString); + + // Strip the source mapping comment. We'll re-add it below if needed. + source = + source.slice(0, sourceMappingStart) + + '\n'.repeat(sourceMappingLines) + + source.slice(sourceMappingEnd); + } + if (useClient) { - return transformClientModule(body, url, loader); + return transformClientModule(program, url, sourceMap, loader); } - return transformServerModule(source, body, url, loader); + return transformServerModule(source, program, url, sourceMap, loader); } export async function transformSource( From 36c04348d7c6179bac4e7f27af823a67289432f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 22 Aug 2024 12:35:49 -0400 Subject: [PATCH 046/426] [DevTools] Make Functions Clickable to Jump to Definition (#30769) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently you can jump to definition of a function by right clicking through the context menu. However, it's pretty difficult to discover. This makes the functions clickable to jump to definition - like links. This uses the same styling as we do for links (which are btw only clickable if they're not editable). Including cursor: pointer. I added a background on hover which follows the same pattern as the owners list. I also dropped the ƒ prefix when displaying functions. This is a cute short cut and there's precedence in how Chrome prints functions in the console *if* the function's toString would've had a function prefix like if it was a function declaration or expression. It does not do this for arrow functions or object methods. Elsewhere in the JS ecosystem this isn't really used anywhere. It invites more questions than it answers. The parenthesis and curlies are enough. There's no ambiguity here since strings have quotations. It looks better with just its object method form. Keeping it simple seems best. To my eyes this flows better because I'm used to looking at function syntax but not weird "f"s. Before: Screenshot 2024-08-20 at 11 55 09 PM After: Screenshot 2024-08-20 at 11 46 01 PM After (Hover): Screenshot 2024-08-20 at 11 46 31 PM --- .../src/__tests__/inspectedElement-test.js | 28 ++++++------- .../__tests__/legacy/inspectElement-test.js | 12 +++--- .../devtools/views/Components/KeyValue.css | 8 ++++ .../src/devtools/views/Components/KeyValue.js | 42 +++++++++++++++++-- packages/react-devtools-shared/src/utils.js | 7 ++-- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index 843c6dff9c08f..cd777f8333763 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -697,8 +697,8 @@ describe('InspectedElement', () => { expect(inspectedElement.props).toMatchInlineSnapshot(` { "anonymous_fn": Dehydrated { - "preview_short": ƒ () {}, - "preview_long": ƒ () {}, + "preview_short": () => {}, + "preview_long": () => {}, }, "array_buffer": Dehydrated { "preview_short": ArrayBuffer(3), @@ -715,8 +715,8 @@ describe('InspectedElement', () => { "preview_long": 123n, }, "bound_fn": Dehydrated { - "preview_short": ƒ bound exampleFunction() {}, - "preview_long": ƒ bound exampleFunction() {}, + "preview_short": bound exampleFunction() {}, + "preview_long": bound exampleFunction() {}, }, "data_view": Dehydrated { "preview_short": DataView(3), @@ -727,8 +727,8 @@ describe('InspectedElement', () => { "preview_long": Tue Dec 31 2019 23:42:42 GMT+0000 (Coordinated Universal Time), }, "fn": Dehydrated { - "preview_short": ƒ exampleFunction() {}, - "preview_long": ƒ exampleFunction() {}, + "preview_short": exampleFunction() {}, + "preview_long": exampleFunction() {}, }, "html_element": Dehydrated { "preview_short":
, @@ -778,8 +778,8 @@ describe('InspectedElement', () => { "Symbol(name)": "hello", }, "proxy": Dehydrated { - "preview_short": ƒ () {}, - "preview_long": ƒ () {}, + "preview_short": () => {}, + "preview_long": () => {}, }, "react_element": Dehydrated { "preview_short": , @@ -2018,16 +2018,16 @@ describe('InspectedElement', () => { { "proxy": { "$$typeof": Dehydrated { - "preview_short": ƒ () {}, - "preview_long": ƒ () {}, + "preview_short": () => {}, + "preview_long": () => {}, }, "Symbol(Symbol.iterator)": Dehydrated { - "preview_short": ƒ () {}, - "preview_long": ƒ () {}, + "preview_short": () => {}, + "preview_long": () => {}, }, "constructor": Dehydrated { - "preview_short": ƒ () {}, - "preview_long": ƒ () {}, + "preview_short": () => {}, + "preview_long": () => {}, }, }, } diff --git a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js index b5941ee5c6ccc..cf1ce1ffa3e38 100644 --- a/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js @@ -212,8 +212,8 @@ describe('InspectedElementContext', () => { expect(inspectedElement.props).toMatchInlineSnapshot(` { "anonymous_fn": Dehydrated { - "preview_short": ƒ () {}, - "preview_long": ƒ () {}, + "preview_short": () => {}, + "preview_long": () => {}, }, "array_buffer": Dehydrated { "preview_short": ArrayBuffer(3), @@ -230,8 +230,8 @@ describe('InspectedElementContext', () => { "preview_long": 123n, }, "bound_fn": Dehydrated { - "preview_short": ƒ bound exampleFunction() {}, - "preview_long": ƒ bound exampleFunction() {}, + "preview_short": bound exampleFunction() {}, + "preview_long": bound exampleFunction() {}, }, "data_view": Dehydrated { "preview_short": DataView(3), @@ -242,8 +242,8 @@ describe('InspectedElementContext', () => { "preview_long": Thu Jan 01 1970 00:00:00 GMT+0000 (Coordinated Universal Time), }, "fn": Dehydrated { - "preview_short": ƒ exampleFunction() {}, - "preview_long": ƒ exampleFunction() {}, + "preview_short": exampleFunction() {}, + "preview_long": exampleFunction() {}, }, "html_element": Dehydrated { "preview_short":
, diff --git a/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.css b/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.css index d6851be672cff..0c0f5e852d9ee 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.css +++ b/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.css @@ -34,8 +34,16 @@ overflow: hidden; text-overflow: ellipsis; flex: 1; + cursor: pointer; + border-radius: 0.125rem; + padding: 0px 2px; } +.Link:hover { + background-color: var(--color-background-hover); +} + + .ExpandCollapseToggleSpacer { flex: 0 0 1rem; width: 1rem; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js b/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js index 16e619cfb0847..af9e4b27e6181 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js @@ -27,7 +27,9 @@ import isArray from 'react-devtools-shared/src/isArray'; import {InspectedElementContext} from './InspectedElementContext'; import {PROTOCOLS_SUPPORTED_AS_LINKS_IN_KEY_VALUE} from './constants'; import KeyValueContextMenuContainer from './KeyValueContextMenuContainer'; +import {ContextMenuContext} from '../context'; +import type {ContextMenuContextType} from '../context'; import type {InspectedElement} from 'react-devtools-shared/src/frontend/types'; import type {Element} from 'react-devtools-shared/src/frontend/types'; import type {Element as ReactElement} from 'react'; @@ -91,6 +93,8 @@ export default function KeyValue({ const contextMenuTriggerRef = useRef(null); const {inspectPaths} = useContext(InspectedElementContext); + const {viewAttributeSourceFunction} = + useContext(ContextMenuContext); let isInspectable = false; let isReadOnlyBasedOnMetadata = false; @@ -268,8 +272,8 @@ export default function KeyValue({ ); + } else if (pathIsFunction && viewAttributeSourceFunction != null) { + children = ( + + )} {listItems.length === 0 && ( -
Did not render during this profiling session.
+
Did not render on the client during this profiling session.
)}
From 9690b9ad749c30eab1900c99e7c25a7ed7e1d9b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 27 Aug 2024 12:05:24 -0400 Subject: [PATCH 060/426] [DevTools] Remove findCurrentFiberUsingSlowPathByFiberInstance (#30818) We always track the last committed Fiber on `FiberInstance.data`. https://github.com/facebook/react/blob/dcae56f8b72f625d8affe5729ca9991b31a492ac/packages/react-devtools-shared/src/backend/fiber/renderer.js#L3068 So we can now remove this complex slow path to get the current fiber. --- .../src/backend/fiber/renderer.js | 221 +----------------- 1 file changed, 7 insertions(+), 214 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index bb5b1b559d5f3..9e5a35686b34f 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -3550,7 +3550,7 @@ export function attach( fiberInstance: FiberInstance, ): $ReadOnlyArray { const hostInstances = []; - const fiber = findCurrentFiberUsingSlowPathByFiberInstance(fiberInstance); + const fiber = fiberInstance.data; if (!fiber) { return hostInstances; } @@ -3601,8 +3601,7 @@ export function attach( // TODO: Handle VirtualInstance. return null; } - const fiber = - findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance); + const fiber = devtoolsInstance.data; if (fiber === null) { return null; } @@ -3710,208 +3709,6 @@ export function attach( return null; } - // This function is copied from React and should be kept in sync: - // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js - function assertIsMounted(fiber: Fiber) { - if (getNearestMountedFiber(fiber) !== fiber) { - throw new Error('Unable to find node on an unmounted component.'); - } - } - - // This function is copied from React and should be kept in sync: - // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js - function getNearestMountedFiber(fiber: Fiber): null | Fiber { - let node = fiber; - let nearestMounted: null | Fiber = fiber; - if (!fiber.alternate) { - // If there is no alternate, this might be a new tree that isn't inserted - // yet. If it is, then it will have a pending insertion effect on it. - let nextNode: Fiber = node; - do { - node = nextNode; - // TODO: This function, and these flags, are a leaked implementation - // detail. Once we start releasing DevTools in lockstep with React, we - // should import a function from the reconciler instead. - const Placement = 0b000000000000000000000000010; - const Hydrating = 0b000000000000001000000000000; - if ((node.flags & (Placement | Hydrating)) !== 0) { - // This is an insertion or in-progress hydration. The nearest possible - // mounted fiber is the parent but we need to continue to figure out - // if that one is still mounted. - nearestMounted = node.return; - } - // $FlowFixMe[incompatible-type] we bail out when we get a null - nextNode = node.return; - } while (nextNode); - } else { - while (node.return) { - node = node.return; - } - } - if (node.tag === HostRoot) { - // TODO: Check if this was a nested HostRoot when used with - // renderContainerIntoSubtree. - return nearestMounted; - } - // If we didn't hit the root, that means that we're in an disconnected tree - // that has been unmounted. - return null; - } - - // This function is copied from React and should be kept in sync: - // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js - // It would be nice if we updated React to inject this function directly (vs just indirectly via findDOMNode). - // BEGIN copied code - function findCurrentFiberUsingSlowPathByFiberInstance( - fiberInstance: FiberInstance, - ): Fiber | null { - const fiber = fiberInstance.data; - const alternate = fiber.alternate; - if (!alternate) { - // If there is no alternate, then we only need to check if it is mounted. - const nearestMounted = getNearestMountedFiber(fiber); - - if (nearestMounted === null) { - throw new Error('Unable to find node on an unmounted component.'); - } - - if (nearestMounted !== fiber) { - return null; - } - return fiber; - } - // If we have two possible branches, we'll walk backwards up to the root - // to see what path the root points to. On the way we may hit one of the - // special cases and we'll deal with them. - let a: Fiber = fiber; - let b: Fiber = alternate; - while (true) { - const parentA = a.return; - if (parentA === null) { - // We're at the root. - break; - } - const parentB = parentA.alternate; - if (parentB === null) { - // There is no alternate. This is an unusual case. Currently, it only - // happens when a Suspense component is hidden. An extra fragment fiber - // is inserted in between the Suspense fiber and its children. Skip - // over this extra fragment fiber and proceed to the next parent. - const nextParent = parentA.return; - if (nextParent !== null) { - a = b = nextParent; - continue; - } - // If there's no parent, we're at the root. - break; - } - - // If both copies of the parent fiber point to the same child, we can - // assume that the child is current. This happens when we bailout on low - // priority: the bailed out fiber's child reuses the current child. - if (parentA.child === parentB.child) { - let child = parentA.child; - while (child) { - if (child === a) { - // We've determined that A is the current branch. - assertIsMounted(parentA); - return fiber; - } - if (child === b) { - // We've determined that B is the current branch. - assertIsMounted(parentA); - return alternate; - } - child = child.sibling; - } - - // We should never have an alternate for any mounting node. So the only - // way this could possibly happen is if this was unmounted, if at all. - throw new Error('Unable to find node on an unmounted component.'); - } - - if (a.return !== b.return) { - // The return pointer of A and the return pointer of B point to different - // fibers. We assume that return pointers never criss-cross, so A must - // belong to the child set of A.return, and B must belong to the child - // set of B.return. - a = parentA; - b = parentB; - } else { - // The return pointers point to the same fiber. We'll have to use the - // default, slow path: scan the child sets of each parent alternate to see - // which child belongs to which set. - // - // Search parent A's child set - let didFindChild = false; - let child = parentA.child; - while (child) { - if (child === a) { - didFindChild = true; - a = parentA; - b = parentB; - break; - } - if (child === b) { - didFindChild = true; - b = parentA; - a = parentB; - break; - } - child = child.sibling; - } - if (!didFindChild) { - // Search parent B's child set - child = parentB.child; - while (child) { - if (child === a) { - didFindChild = true; - a = parentB; - b = parentA; - break; - } - if (child === b) { - didFindChild = true; - b = parentB; - a = parentA; - break; - } - child = child.sibling; - } - - if (!didFindChild) { - throw new Error( - 'Child was not found in either parent set. This indicates a bug ' + - 'in React related to the return pointer. Please file an issue.', - ); - } - } - } - - if (a.alternate !== b) { - throw new Error( - "Return fibers should always be each others' alternates. " + - 'This error is likely caused by a bug in React. Please file an issue.', - ); - } - } - - // If the root is not a host container, we're in a disconnected tree. I.e. - // unmounted. - if (a.tag !== HostRoot) { - throw new Error('Unable to find node on an unmounted component.'); - } - - if (a.stateNode.current === a) { - // We've determined that A is the current branch. - return fiber; - } - // Otherwise B has to be current branch. - return alternate; - } - - // END copied code - function getElementAttributeByPath( id: number, path: Array, @@ -4096,8 +3893,7 @@ export function attach( return {instance, style}; } - const fiber = - findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance); + const fiber = devtoolsInstance.data; if (fiber !== null) { instance = fiber.stateNode; @@ -4153,7 +3949,7 @@ export function attach( function inspectFiberInstanceRaw( fiberInstance: FiberInstance, ): InspectedElement | null { - const fiber = findCurrentFiberUsingSlowPathByFiberInstance(fiberInstance); + const fiber = fiberInstance.data; if (fiber == null) { return null; } @@ -4913,8 +4709,7 @@ export function attach( // TODO: Handle VirtualInstance. return; } - const fiber = - findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance); + const fiber = devtoolsInstance.data; if (fiber !== null) { const instance = fiber.stateNode; @@ -4979,8 +4774,7 @@ export function attach( // TODO: Handle VirtualInstance. return; } - const fiber = - findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance); + const fiber = devtoolsInstance.data; if (fiber !== null) { const instance = fiber.stateNode; @@ -5055,8 +4849,7 @@ export function attach( // TODO: Handle VirtualInstance. return; } - const fiber = - findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance); + const fiber = devtoolsInstance.data; if (fiber !== null) { const instance = fiber.stateNode; From f90a6bcc4c988f7524ce2be675b3257a530a51e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 27 Aug 2024 12:05:47 -0400 Subject: [PATCH 061/426] [DevTools] Reconcile Fibers Against Previous Children Instances (#30822) This loops over the remainingReconcilingChildren to find existing FiberInstances that match the updated Fiber. This is the same thing we already do for virtual instances. This avoids the need for a `fiberToFiberInstanceMap`. This loop is fast but there is a downside when the children set is very large and gets reordered with keys since we might have to loop over the set multiple times to get to the instances in the bottom. If that becomes a problem we can optimize it the same way ReactChildFiber does which is to create a temporary Map only when the children don't line up properly. That way everything except the first pass can use the Map but there's no need to create it eagerly. Now that we have the loop we don't need the previousSibling field so we can save some memory there. --- .../src/backend/fiber/renderer.js | 166 ++++++++++-------- 1 file changed, 89 insertions(+), 77 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 9e5a35686b34f..729c8fce5a7a5 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -158,7 +158,6 @@ type FiberInstance = { id: number, parent: null | DevToolsInstance, // filtered parent, including virtual firstChild: null | DevToolsInstance, // filtered first child, including virtual - previousSibling: null | DevToolsInstance, // filtered next sibling, including virtual nextSibling: null | DevToolsInstance, // filtered next sibling, including virtual flags: number, // Force Error/Suspense source: null | string | Error | Source, // source location of this component function, or owned child stack @@ -174,7 +173,6 @@ function createFiberInstance(fiber: Fiber): FiberInstance { id: getUID(), parent: null, firstChild: null, - previousSibling: null, nextSibling: null, flags: 0, source: null, @@ -195,7 +193,6 @@ type VirtualInstance = { id: number, parent: null | DevToolsInstance, // filtered parent, including virtual firstChild: null | DevToolsInstance, // filtered first child, including virtual - previousSibling: null | DevToolsInstance, // filtered next sibling, including virtual nextSibling: null | DevToolsInstance, // filtered next sibling, including virtual flags: number, source: null | string | Error | Source, // source location of this server component, or owned child stack @@ -218,7 +215,6 @@ function createVirtualInstance( id: getUID(), parent: null, firstChild: null, - previousSibling: null, nextSibling: null, flags: 0, source: null, @@ -1088,8 +1084,6 @@ export function attach( ' '.repeat(indent) + '- ' + instance.id + ' (' + name + ')', 'parent', instance.parent === null ? ' ' : instance.parent.id, - 'prev', - instance.previousSibling === null ? ' ' : instance.previousSibling.id, 'next', instance.nextSibling === null ? ' ' : instance.nextSibling.id, ); @@ -2321,21 +2315,25 @@ export function attach( if (previouslyReconciledSibling === null) { previouslyReconciledSibling = instance; parentInstance.firstChild = instance; - instance.previousSibling = null; } else { previouslyReconciledSibling.nextSibling = instance; - instance.previousSibling = previouslyReconciledSibling; previouslyReconciledSibling = instance; } instance.nextSibling = null; } - function moveChild(instance: DevToolsInstance): void { - removeChild(instance); + function moveChild( + instance: DevToolsInstance, + previousSibling: null | DevToolsInstance, + ): void { + removeChild(instance, previousSibling); insertChild(instance); } - function removeChild(instance: DevToolsInstance): void { + function removeChild( + instance: DevToolsInstance, + previousSibling: null | DevToolsInstance, + ): void { if (instance.parent === null) { if (remainingReconcilingChildren === instance) { throw new Error( @@ -2343,8 +2341,6 @@ export function attach( ); } else if (instance.nextSibling !== null) { throw new Error('A deleted instance should not have next siblings'); - } else if (instance.previousSibling !== null) { - throw new Error('A deleted instance should not have previous siblings'); } // Already deleted. return; @@ -2360,7 +2356,7 @@ export function attach( } // Remove an existing child from its current position, which we assume is in the // remainingReconcilingChildren set. - if (instance.previousSibling === null) { + if (previousSibling === null) { // We're first in the remaining set. Remove us. if (remainingReconcilingChildren !== instance) { throw new Error( @@ -2369,13 +2365,9 @@ export function attach( } remainingReconcilingChildren = instance.nextSibling; } else { - instance.previousSibling.nextSibling = instance.nextSibling; - } - if (instance.nextSibling !== null) { - instance.nextSibling.previousSibling = instance.previousSibling; + previousSibling.nextSibling = instance.nextSibling; } instance.nextSibling = null; - instance.previousSibling = null; instance.parent = null; } @@ -2655,7 +2647,7 @@ export function attach( } else { recordVirtualUnmount(instance); } - removeChild(instance); + removeChild(instance, null); } function recordProfilingDurations(fiberInstance: FiberInstance) { @@ -2889,8 +2881,7 @@ export function attach( ); } } - // TODO: Find the best matching existing child based on the key if defined. - + let previousSiblingOfBestMatch = null; let bestMatch = remainingReconcilingChildren; if (componentInfo.key != null) { // If there is a key try to find a matching key in the set. @@ -2902,6 +2893,7 @@ export function attach( ) { break; } + previousSiblingOfBestMatch = bestMatch; bestMatch = bestMatch.nextSibling; } } @@ -2916,7 +2908,7 @@ export function attach( // with the same name, then we claim it and reuse it for this update. // Update it with the latest entry. bestMatch.data = componentInfo; - moveChild(bestMatch); + moveChild(bestMatch, previousSiblingOfBestMatch); previousVirtualInstance = bestMatch; previousVirtualInstanceWasMount = false; } else { @@ -2965,42 +2957,93 @@ export function attach( } previousVirtualInstance = null; } + // We've reached the end of the virtual levels, but not beyond, // and now continue with the regular fiber. + + // Do a fast pass over the remaining children to find the previous instance. + // TODO: This doesn't have the best O(n) for a large set of children that are + // reordered. Consider using a temporary map if it's not the very next one. + let prevChild; if (prevChildAtSameIndex === nextChild) { // This set is unchanged. We're just going through it to place all the // children again. + prevChild = nextChild; + } else { + // We don't actually need to rely on the alternate here. We could also + // reconcile against stateNode, key or whatever. Doesn't have to be same + // Fiber pair. + prevChild = nextChild.alternate; + } + let previousSiblingOfExistingInstance = null; + let existingInstance = null; + if (prevChild !== null) { + existingInstance = remainingReconcilingChildren; + while (existingInstance !== null) { + if (existingInstance.data === prevChild) { + break; + } + previousSiblingOfExistingInstance = existingInstance; + existingInstance = existingInstance.nextSibling; + } + } + if (existingInstance !== null) { + // Common case. Match in the same parent. + const fiberInstance: FiberInstance = (existingInstance: any); // Only matches if it's a Fiber. + + // We keep track if the order of the children matches the previous order. + // They are always different referentially, but if the instances line up + // conceptually we'll want to know that. + if (prevChild !== prevChildAtSameIndex) { + shouldResetChildren = true; + } + + // Register the new alternate in case it's not already in. + fiberToFiberInstanceMap.set(nextChild, fiberInstance); + + // Update the Fiber so we that we always keep the current Fiber on the data. + fiberInstance.data = nextChild; + moveChild(fiberInstance, previousSiblingOfExistingInstance); + if ( updateFiberRecursively( + fiberInstance, nextChild, - nextChild, + (prevChild: any), traceNearestHostComponentUpdate, ) ) { - throw new Error('Updating the same fiber should not cause reorder'); + // If a nested tree child order changed but it can't handle its own + // child order invalidation (e.g. because it's filtered out like host nodes), + // propagate the need to reset child order upwards to this Fiber. + shouldResetChildren = true; } - } else if (nextChild.alternate) { - const prevChild = nextChild.alternate; + } else if (prevChild !== null && shouldFilterFiber(nextChild)) { + // If this Fiber should be filtered, we need to still update its children. + // This relies on an alternate since we don't have an Instance with the previous + // child on it. Ideally, the reconciliation wouldn't need previous Fibers that + // are filtered from the tree. if ( updateFiberRecursively( + null, nextChild, prevChild, traceNearestHostComponentUpdate, ) ) { - // If a nested tree child order changed but it can't handle its own - // child order invalidation (e.g. because it's filtered out like host nodes), - // propagate the need to reset child order upwards to this Fiber. - shouldResetChildren = true; - } - // However we also keep track if the order of the children matches - // the previous order. They are always different referentially, but - // if the instances line up conceptually we'll want to know that. - if (prevChild !== prevChildAtSameIndex) { shouldResetChildren = true; } } else { + // It's possible for a FiberInstance to be reparented when virtual parents + // get their sequence split or change structure with the same render result. + // In this case we unmount the and remount the FiberInstances. + // This might cause us to lose the selection but it's an edge case. + + // We let the previous instance remain in the "remaining queue" it is + // in to be deleted at the end since it'll have no match. + mountFiberRecursively(nextChild, traceNearestHostComponentUpdate); + // Need to mark the parent set to remount the new instance. shouldResetChildren = true; } } @@ -3059,6 +3102,7 @@ export function attach( // Returns whether closest unfiltered fiber parent needs to reset its child list. function updateFiberRecursively( + fiberInstance: null | FiberInstance, // null if this should be filtered nextFiber: Fiber, prevFiber: Fiber, traceNearestHostComponentUpdate: boolean, @@ -3092,34 +3136,10 @@ export function attach( } } - let fiberInstance: null | FiberInstance = null; - const shouldIncludeInTree = !shouldFilterFiber(nextFiber); - if (shouldIncludeInTree) { - const entry = fiberToFiberInstanceMap.get(prevFiber); - if (entry !== undefined && entry.parent === reconcilingParent) { - // Common case. Match in the same parent. - fiberInstance = entry; - // Register the new alternate in case it's not already in. - fiberToFiberInstanceMap.set(nextFiber, fiberInstance); - - // Update the Fiber so we that we always keep the current Fiber on the data. - fiberInstance.data = nextFiber; - moveChild(fiberInstance); - } else { - // It's possible for a FiberInstance to be reparented when virtual parents - // get their sequence split or change structure with the same render result. - // In this case we unmount the and remount the FiberInstances. - // This might cause us to lose the selection but it's an edge case. - - // We let the previous instance remain in the "remaining queue" it is - // in to be deleted at the end since it'll have no match. - - mountFiberRecursively(nextFiber, traceNearestHostComponentUpdate); - - // Need to mark the parent set to remount the new instance. - return true; - } - + const stashedParent = reconcilingParent; + const stashedPrevious = previouslyReconciledSibling; + const stashedRemaining = remainingReconcilingChildren; + if (fiberInstance !== null) { if ( mostRecentlyInspectedElement !== null && mostRecentlyInspectedElement.id === fiberInstance.id && @@ -3129,12 +3149,6 @@ export function attach( // If it is inspected again, it may need to be re-run to obtain updated hooks values. hasElementUpdatedSinceLastInspected = true; } - } - - const stashedParent = reconcilingParent; - const stashedPrevious = previouslyReconciledSibling; - const stashedRemaining = remainingReconcilingChildren; - if (fiberInstance !== null) { // Push a new DevTools instance parent while reconciling this subtree. reconcilingParent = fiberInstance; previouslyReconciledSibling = null; @@ -3189,7 +3203,7 @@ export function attach( if ( nextFallbackChildSet != null && prevFallbackChildSet != null && - updateFiberRecursively( + updateChildrenRecursively( nextFallbackChildSet, prevFallbackChildSet, traceNearestHostComponentUpdate, @@ -3284,10 +3298,8 @@ export function attach( if (shouldResetChildren) { // We need to crawl the subtree for closest non-filtered Fibers // so that we can display them in a flat children set. - if (shouldIncludeInTree) { - if (reconcilingParent !== null) { - recordResetChildren(reconcilingParent); - } + if (fiberInstance !== null) { + recordResetChildren(fiberInstance); // We've handled the child order change for this Fiber. // Since it's included, there's no need to invalidate parent child order. return false; @@ -3299,7 +3311,7 @@ export function attach( return false; } } finally { - if (shouldIncludeInTree) { + if (fiberInstance !== null) { unmountRemainingChildren(); reconcilingParent = stashedParent; previouslyReconciledSibling = stashedPrevious; @@ -3489,7 +3501,7 @@ export function attach( mountFiberRecursively(current, false); } else if (wasMounted && isMounted) { // Update an existing root. - updateFiberRecursively(current, alternate, false); + updateFiberRecursively(rootInstance, current, alternate, false); } else if (wasMounted && !isMounted) { // Unmount an existing root. removeRootPseudoKey(currentRootID); From 96aca5f4f3d7fbe0c13350f90031d8ec4c060ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 27 Aug 2024 13:10:37 -0400 Subject: [PATCH 062/426] Spawn new task if we hit stack overflow (#30419) If we see the "Maximum call stack size exceeded" error we know we've hit stack overflow. We can recover from this by spawning a new task and trying again. Effectively a zero-cost trampoline in the normal case. The new task will have a clean stack. If you have a lot of siblings at the same depth that hits the limit you can end up hitting this once for each sibling but within that new sibling you're unlikely to hit this again. So it's not too expensive. If it errors again in the retryTask pass, the other error handling takes over which causes this to be able to still not infinitely stall. E.g. when the component itself throws an error like this. It's still better to increase the stack limit for performance if you have a really deep tree but it doesn't really hurt to be able to recover since it's zero cost when it doesn't happen. We could do the same thing for Flight. Those trees don't tend to be as deep but could happen. --- .../src/__tests__/ReactDOMFizzServer-test.js | 61 ++++++++++++ packages/react-server/src/ReactFizzServer.js | 92 +++++++++++++++---- 2 files changed, 137 insertions(+), 16 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index 5a763ffe949ab..a109011b35e98 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -8677,4 +8677,65 @@ describe('ReactDOMFizzServer', () => { '\n in Bar (at **)' + '\n in Foo (at **)', ); }); + + it('can recover from very deep trees to avoid stack overflow', async () => { + function Recursive({n}) { + if (n > 0) { + return ; + } + return hi; + } + + // Recursively render a component tree deep enough to trigger stack overflow. + // Don't make this too short to not hit the limit but also not too deep to slow + // down the test. + await act(() => { + const {pipe} = renderToPipeableStream( +
+ +
, + ); + pipe(writable); + }); + + expect(getVisibleChildren(container)).toEqual( +
+ hi +
, + ); + }); + + it('handles stack overflows inside components themselves', async () => { + function StackOverflow() { + // This component is recursive inside itself and is therefore an error. + // Assuming no tail-call optimizations. + function recursive(n, a0, a1, a2, a3) { + if (n > 0) { + return recursive(n - 1, a0, a1, a2, a3) + a0 + a1 + a2 + a3; + } + return a0; + } + return recursive(10000, 'should', 'not', 'resolve', 'this'); + } + + let caughtError; + + await expect(async () => { + await act(() => { + const {pipe} = renderToPipeableStream( +
+ +
, + { + onError(error, errorInfo) { + caughtError = error; + }, + }, + ); + pipe(writable); + }); + }).rejects.toThrow('Maximum call stack size exceeded'); + + expect(caughtError.message).toBe('Maximum call stack size exceeded'); + }); }); diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index 7ccbd65d16b74..aeffa6b813b8f 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -3320,9 +3320,8 @@ function spawnNewSuspendedReplayTask( request: Request, task: ReplayTask, thenableState: ThenableState | null, - x: Wakeable, -): void { - const newTask = createReplayTask( +): ReplayTask { + return createReplayTask( request, thenableState, task.replay, @@ -3340,17 +3339,13 @@ function spawnNewSuspendedReplayTask( !disableLegacyContext ? task.legacyContext : emptyContextObject, __DEV__ && enableOwnerStacks ? task.debugTask : null, ); - - const ping = newTask.ping; - x.then(ping, ping); } function spawnNewSuspendedRenderTask( request: Request, task: RenderTask, thenableState: ThenableState | null, - x: Wakeable, -): void { +): RenderTask { // Something suspended, we'll need to create a new segment and resolve it later. const segment = task.blockedSegment; const insertionIndex = segment.chunks.length; @@ -3367,7 +3362,7 @@ function spawnNewSuspendedRenderTask( segment.children.push(newSegment); // Reset lastPushedText for current Segment since the new Segment "consumed" it segment.lastPushedText = false; - const newTask = createRenderTask( + return createRenderTask( request, thenableState, task.node, @@ -3385,9 +3380,6 @@ function spawnNewSuspendedRenderTask( !disableLegacyContext ? task.legacyContext : emptyContextObject, __DEV__ && enableOwnerStacks ? task.debugTask : null, ); - - const ping = newTask.ping; - x.then(ping, ping); } // This is a non-destructive form of rendering a node. If it suspends it spawns @@ -3436,14 +3428,48 @@ function renderNode( if (typeof x.then === 'function') { const wakeable: Wakeable = (x: any); const thenableState = getThenableStateAfterSuspending(); - spawnNewSuspendedReplayTask( + const newTask = spawnNewSuspendedReplayTask( + request, + // $FlowFixMe: Refined. + task, + thenableState, + ); + const ping = newTask.ping; + wakeable.then(ping, ping); + + // Restore the context. We assume that this will be restored by the inner + // functions in case nothing throws so we don't use "finally" here. + task.formatContext = previousFormatContext; + if (!disableLegacyContext) { + task.legacyContext = previousLegacyContext; + } + task.context = previousContext; + task.keyPath = previousKeyPath; + task.treeContext = previousTreeContext; + task.componentStack = previousComponentStack; + if (__DEV__ && enableOwnerStacks) { + task.debugTask = previousDebugTask; + } + // Restore all active ReactContexts to what they were before. + switchContext(previousContext); + return; + } + if (x.message === 'Maximum call stack size exceeded') { + // This was a stack overflow. We do a lot of recursion in React by default for + // performance but it can lead to stack overflows in extremely deep trees. + // We do have the ability to create a trampoile if this happens which makes + // this kind of zero-cost. + const thenableState = getThenableStateAfterSuspending(); + const newTask = spawnNewSuspendedReplayTask( request, // $FlowFixMe: Refined. task, thenableState, - wakeable, ); + // Immediately schedule the task for retrying. + request.pingedTasks.push(newTask); + // Restore the context. We assume that this will be restored by the inner // functions in case nothing throws so we don't use "finally" here. task.formatContext = previousFormatContext; @@ -3493,13 +3519,14 @@ function renderNode( if (typeof x.then === 'function') { const wakeable: Wakeable = (x: any); const thenableState = getThenableStateAfterSuspending(); - spawnNewSuspendedRenderTask( + const newTask = spawnNewSuspendedRenderTask( request, // $FlowFixMe: Refined. task, thenableState, - wakeable, ); + const ping = newTask.ping; + wakeable.then(ping, ping); // Restore the context. We assume that this will be restored by the inner // functions in case nothing throws so we don't use "finally" here. @@ -3540,6 +3567,39 @@ function renderNode( ); trackPostpone(request, trackedPostpones, task, postponedSegment); + // Restore the context. We assume that this will be restored by the inner + // functions in case nothing throws so we don't use "finally" here. + task.formatContext = previousFormatContext; + if (!disableLegacyContext) { + task.legacyContext = previousLegacyContext; + } + task.context = previousContext; + task.keyPath = previousKeyPath; + task.treeContext = previousTreeContext; + task.componentStack = previousComponentStack; + if (__DEV__ && enableOwnerStacks) { + task.debugTask = previousDebugTask; + } + // Restore all active ReactContexts to what they were before. + switchContext(previousContext); + return; + } + if (x.message === 'Maximum call stack size exceeded') { + // This was a stack overflow. We do a lot of recursion in React by default for + // performance but it can lead to stack overflows in extremely deep trees. + // We do have the ability to create a trampoile if this happens which makes + // this kind of zero-cost. + const thenableState = getThenableStateAfterSuspending(); + const newTask = spawnNewSuspendedRenderTask( + request, + // $FlowFixMe: Refined. + task, + thenableState, + ); + + // Immediately schedule the task for retrying. + request.pingedTasks.push(newTask); + // Restore the context. We assume that this will be restored by the inner // functions in case nothing throws so we don't use "finally" here. task.formatContext = previousFormatContext; From f2841c2a490b4b776b98568871b69693fedf985c Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Tue, 27 Aug 2024 10:11:50 -0700 Subject: [PATCH 063/426] [compiler] Fixture to demonstrate issue with returning object containing ref Summary: We currently can return a ref from a hook but not an object containing a ref. ghstack-source-id: 8b1de4991eb2731b7f758e685ba62d9f07d584b2 Pull Request resolved: https://github.com/facebook/react/pull/30820 --- ...or.return-ref-callback-structure.expect.md | 45 +++++++++++++++++++ .../error.return-ref-callback-structure.js | 20 +++++++++ 2 files changed, 65 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md new file mode 100644 index 0000000000000..866d2e2fea657 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md @@ -0,0 +1,45 @@ + +## Input + +```javascript +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +import {useRef} from 'react'; + +component Foo(cond: boolean, cond2: boolean) { + const ref = useRef(); + + const s = () => { + return ref.current; + }; + + if (cond) return [s]; + else if (cond2) return {s}; + else return {s: [s]}; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{cond: false, cond2: false}], +}; + +``` + + +## Error + +``` + 10 | }; + 11 | +> 12 | if (cond) return [s]; + | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (13:13) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) + 13 | else if (cond2) return {s}; + 14 | else return {s: [s]}; + 15 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.js new file mode 100644 index 0000000000000..e37acbde348d1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.js @@ -0,0 +1,20 @@ +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +import {useRef} from 'react'; + +component Foo(cond: boolean, cond2: boolean) { + const ref = useRef(); + + const s = () => { + return ref.current; + }; + + if (cond) return [s]; + else if (cond2) return {s}; + else return {s: [s]}; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{cond: false, cond2: false}], +}; From 7771d3a7972cc2483c45fde51b7ec2d926cba097 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Tue, 27 Aug 2024 10:11:50 -0700 Subject: [PATCH 064/426] [compiler] Track refs through object expressions and property lookups Summary: This addresses the issue of the compiler being overly restrictive about refs escaping into object expressions. Rather than erroring whenever a ref flows into an object, we will now treat the object itself as a ref, and apply the same escape rules to it. Whenever we look up a property from a ref value, we now don't know whether that value is itself a ref or a ref value, so we assume it's both. The same logic applies to ref-accessing functions--if such a function is stored in an object, we'll propagate that property to the object itself and any properties looked up from it. ghstack-source-id: 5c6fcb895d4a1658ce9dddec286aad3a57a4c9f1 Pull Request resolved: https://github.com/facebook/react/pull/30821 --- .../Validation/ValidateNoRefAccesInRender.ts | 253 ++++++++++++------ ...f-added-to-dep-without-type-info.expect.md | 16 +- ...or.return-ref-callback-structure.expect.md | 45 ---- .../return-ref-callback-structure.expect.md | 87 ++++++ ...re.js => return-ref-callback-structure.js} | 0 5 files changed, 273 insertions(+), 128 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.return-ref-callback-structure.js => return-ref-callback-structure.js} (100%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index df6241a73f448..8a65b4709c174 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -11,12 +11,12 @@ import { IdentifierId, Place, SourceLocation, - isRefOrRefValue, isRefValueType, isUseRefType, } from '../HIR'; import { eachInstructionValueOperand, + eachPatternOperand, eachTerminalOperand, } from '../HIR/visitors'; import {Err, Ok, Result} from '../Utils/Result'; @@ -42,58 +42,165 @@ import {isEffectHook} from './ValidateMemoizedEffectDependencies'; * In the future we may reject more cases, based on either object names (`fooRef.current` is likely a ref) * or based on property name alone (`foo.current` might be a ref). */ +type State = { + refs: Set; + refValues: Map; + refAccessingFunctions: Set; +}; + export function validateNoRefAccessInRender(fn: HIRFunction): void { - const refAccessingFunctions: Set = new Set(); - validateNoRefAccessInRenderImpl(fn, refAccessingFunctions).unwrap(); + const state = { + refs: new Set(), + refValues: new Map(), + refAccessingFunctions: new Set(), + }; + validateNoRefAccessInRenderImpl(fn, state).unwrap(); } function validateNoRefAccessInRenderImpl( fn: HIRFunction, - refAccessingFunctions: Set, + state: State, ): Result { + let place; + for (const param of fn.params) { + if (param.kind === 'Identifier') { + place = param; + } else { + place = param.place; + } + + if (isRefValueType(place.identifier)) { + state.refValues.set(place.identifier.id, null); + } + if (isUseRefType(place.identifier)) { + state.refs.add(place.identifier.id); + } + } const errors = new CompilerError(); - const lookupLocations: Map = new Map(); for (const [, block] of fn.body.blocks) { + for (const phi of block.phis) { + phi.operands.forEach(operand => { + if (state.refs.has(operand.id) || isUseRefType(phi.id)) { + state.refs.add(phi.id.id); + } + const refValue = state.refValues.get(operand.id); + if (refValue !== undefined || isRefValueType(operand)) { + state.refValues.set( + phi.id.id, + refValue ?? state.refValues.get(phi.id.id) ?? null, + ); + } + if (state.refAccessingFunctions.has(operand.id)) { + state.refAccessingFunctions.add(phi.id.id); + } + }); + } + for (const instr of block.instructions) { + for (const operand of eachInstructionValueOperand(instr.value)) { + if (isRefValueType(operand.identifier)) { + CompilerError.invariant(state.refValues.has(operand.identifier.id), { + reason: 'Expected ref value to be in state', + loc: operand.loc, + }); + } + if (isUseRefType(operand.identifier)) { + CompilerError.invariant(state.refs.has(operand.identifier.id), { + reason: 'Expected ref to be in state', + loc: operand.loc, + }); + } + } + switch (instr.value.kind) { case 'JsxExpression': case 'JsxFragment': { for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoDirectRefValueAccess(errors, operand, lookupLocations); + validateNoDirectRefValueAccess(errors, operand, state); } break; } + case 'ComputedLoad': case 'PropertyLoad': { + if (typeof instr.value.property !== 'string') { + validateNoRefValueAccess(errors, state, instr.value.property); + } if ( - isRefValueType(instr.lvalue.identifier) && - instr.value.property === 'current' + state.refAccessingFunctions.has(instr.value.object.identifier.id) ) { - lookupLocations.set(instr.lvalue.identifier.id, instr.loc); + state.refAccessingFunctions.add(instr.lvalue.identifier.id); + } + if (state.refs.has(instr.value.object.identifier.id)) { + /* + * Once an object contains a ref at any level, we treat it as a ref. + * If we look something up from it, that value may either be a ref + * or the ref value (or neither), so we conservatively assume it's both. + */ + state.refs.add(instr.lvalue.identifier.id); + state.refValues.set(instr.lvalue.identifier.id, instr.loc); } break; } + case 'LoadContext': case 'LoadLocal': { - if (refAccessingFunctions.has(instr.value.place.identifier.id)) { - refAccessingFunctions.add(instr.lvalue.identifier.id); + if ( + state.refAccessingFunctions.has(instr.value.place.identifier.id) + ) { + state.refAccessingFunctions.add(instr.lvalue.identifier.id); } - if (isRefValueType(instr.lvalue.identifier)) { - const loc = lookupLocations.get(instr.value.place.identifier.id); - if (loc !== undefined) { - lookupLocations.set(instr.lvalue.identifier.id, loc); - } + const refValue = state.refValues.get(instr.value.place.identifier.id); + if (refValue !== undefined) { + state.refValues.set(instr.lvalue.identifier.id, refValue); + } + if (state.refs.has(instr.value.place.identifier.id)) { + state.refs.add(instr.lvalue.identifier.id); } break; } + case 'StoreContext': case 'StoreLocal': { - if (refAccessingFunctions.has(instr.value.value.identifier.id)) { - refAccessingFunctions.add(instr.value.lvalue.place.identifier.id); - refAccessingFunctions.add(instr.lvalue.identifier.id); + if ( + state.refAccessingFunctions.has(instr.value.value.identifier.id) + ) { + state.refAccessingFunctions.add( + instr.value.lvalue.place.identifier.id, + ); + state.refAccessingFunctions.add(instr.lvalue.identifier.id); + } + const refValue = state.refValues.get(instr.value.value.identifier.id); + if ( + refValue !== undefined || + isRefValueType(instr.value.lvalue.place.identifier) + ) { + state.refValues.set( + instr.value.lvalue.place.identifier.id, + refValue ?? null, + ); + state.refValues.set(instr.lvalue.identifier.id, refValue ?? null); + } + if (state.refs.has(instr.value.value.identifier.id)) { + state.refs.add(instr.value.lvalue.place.identifier.id); + state.refs.add(instr.lvalue.identifier.id); } - if (isRefValueType(instr.value.lvalue.place.identifier)) { - const loc = lookupLocations.get(instr.value.value.identifier.id); - if (loc !== undefined) { - lookupLocations.set(instr.value.lvalue.place.identifier.id, loc); - lookupLocations.set(instr.lvalue.identifier.id, loc); + break; + } + case 'Destructure': { + const destructuredFunction = state.refAccessingFunctions.has( + instr.value.value.identifier.id, + ); + const destructuredRef = state.refs.has( + instr.value.value.identifier.id, + ); + for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) { + if (isUseRefType(lval.identifier)) { + state.refs.add(lval.identifier.id); + } + if (destructuredRef || isRefValueType(lval.identifier)) { + state.refs.add(lval.identifier.id); + state.refValues.set(lval.identifier.id, null); + } + if (destructuredFunction) { + state.refAccessingFunctions.add(lval.identifier.id); } } break; @@ -107,32 +214,27 @@ function validateNoRefAccessInRenderImpl( */ [...eachInstructionValueOperand(instr.value)].some( operand => - isRefValueType(operand.identifier) || - refAccessingFunctions.has(operand.identifier.id), + state.refValues.has(operand.identifier.id) || + state.refAccessingFunctions.has(operand.identifier.id), ) || // check for cases where .current is accessed through an aliased ref ([...eachInstructionValueOperand(instr.value)].some(operand => - isUseRefType(operand.identifier), + state.refs.has(operand.identifier.id), ) && validateNoRefAccessInRenderImpl( instr.value.loweredFunc.func, - refAccessingFunctions, + state, ).isErr()) ) { // This function expression unconditionally accesses a ref - refAccessingFunctions.add(instr.lvalue.identifier.id); + state.refAccessingFunctions.add(instr.lvalue.identifier.id); } break; } case 'MethodCall': { if (!isEffectHook(instr.value.property.identifier)) { for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefAccess( - errors, - refAccessingFunctions, - operand, - operand.loc, - ); + validateNoRefAccess(errors, state, operand, operand.loc); } } break; @@ -142,7 +244,7 @@ function validateNoRefAccessInRenderImpl( const isUseEffect = isEffectHook(callee.identifier); if (!isUseEffect) { // Report a more precise error when calling a local function that accesses a ref - if (refAccessingFunctions.has(callee.identifier.id)) { + if (state.refAccessingFunctions.has(callee.identifier.id)) { errors.push({ severity: ErrorSeverity.InvalidReact, reason: @@ -159,9 +261,9 @@ function validateNoRefAccessInRenderImpl( for (const operand of eachInstructionValueOperand(instr.value)) { validateNoRefAccess( errors, - refAccessingFunctions, + state, operand, - lookupLocations.get(operand.identifier.id) ?? operand.loc, + state.refValues.get(operand.identifier.id) ?? operand.loc, ); } } @@ -170,12 +272,17 @@ function validateNoRefAccessInRenderImpl( case 'ObjectExpression': case 'ArrayExpression': { for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefAccess( - errors, - refAccessingFunctions, - operand, - lookupLocations.get(operand.identifier.id) ?? operand.loc, - ); + validateNoDirectRefValueAccess(errors, operand, state); + if (state.refAccessingFunctions.has(operand.identifier.id)) { + state.refAccessingFunctions.add(instr.lvalue.identifier.id); + } + if (state.refs.has(operand.identifier.id)) { + state.refs.add(instr.lvalue.identifier.id); + } + const refValue = state.refValues.get(operand.identifier.id); + if (refValue !== undefined) { + state.refValues.set(instr.lvalue.identifier.id, refValue); + } } break; } @@ -185,20 +292,15 @@ function validateNoRefAccessInRenderImpl( case 'ComputedStore': { validateNoRefAccess( errors, - refAccessingFunctions, + state, instr.value.object, - lookupLocations.get(instr.value.object.identifier.id) ?? instr.loc, + state.refValues.get(instr.value.object.identifier.id) ?? instr.loc, ); for (const operand of eachInstructionValueOperand(instr.value)) { if (operand === instr.value.object) { continue; } - validateNoRefValueAccess( - errors, - refAccessingFunctions, - lookupLocations, - operand, - ); + validateNoRefValueAccess(errors, state, operand); } break; } @@ -207,28 +309,27 @@ function validateNoRefAccessInRenderImpl( break; default: { for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefValueAccess( - errors, - refAccessingFunctions, - lookupLocations, - operand, - ); + validateNoRefValueAccess(errors, state, operand); } break; } } + if (isUseRefType(instr.lvalue.identifier)) { + state.refs.add(instr.lvalue.identifier.id); + } + if ( + isRefValueType(instr.lvalue.identifier) && + !state.refValues.has(instr.lvalue.identifier.id) + ) { + state.refValues.set(instr.lvalue.identifier.id, instr.loc); + } } for (const operand of eachTerminalOperand(block.terminal)) { if (block.terminal.kind !== 'return') { - validateNoRefValueAccess( - errors, - refAccessingFunctions, - lookupLocations, - operand, - ); + validateNoRefValueAccess(errors, state, operand); } else { // Allow functions containing refs to be returned, but not direct ref values - validateNoDirectRefValueAccess(errors, operand, lookupLocations); + validateNoDirectRefValueAccess(errors, operand, state); } } } @@ -242,19 +343,18 @@ function validateNoRefAccessInRenderImpl( function validateNoRefValueAccess( errors: CompilerError, - refAccessingFunctions: Set, - lookupLocations: Map, + state: State, operand: Place, ): void { if ( - isRefValueType(operand.identifier) || - refAccessingFunctions.has(operand.identifier.id) + state.refValues.has(operand.identifier.id) || + state.refAccessingFunctions.has(operand.identifier.id) ) { errors.push({ severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: lookupLocations.get(operand.identifier.id) ?? operand.loc, + loc: state.refValues.get(operand.identifier.id) ?? operand.loc, description: operand.identifier.name !== null && operand.identifier.name.kind === 'named' @@ -267,13 +367,14 @@ function validateNoRefValueAccess( function validateNoRefAccess( errors: CompilerError, - refAccessingFunctions: Set, + state: State, operand: Place, loc: SourceLocation, ): void { if ( - isRefOrRefValue(operand.identifier) || - refAccessingFunctions.has(operand.identifier.id) + state.refs.has(operand.identifier.id) || + state.refValues.has(operand.identifier.id) || + state.refAccessingFunctions.has(operand.identifier.id) ) { errors.push({ severity: ErrorSeverity.InvalidReact, @@ -293,14 +394,14 @@ function validateNoRefAccess( function validateNoDirectRefValueAccess( errors: CompilerError, operand: Place, - lookupLocations: Map, + state: State, ): void { - if (isRefValueType(operand.identifier)) { + if (state.refValues.has(operand.identifier.id)) { errors.push({ severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: lookupLocations.get(operand.identifier.id) ?? operand.loc, + loc: state.refValues.get(operand.identifier.id) ?? operand.loc, description: operand.identifier.name !== null && operand.identifier.name.kind === 'named' diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md index a28a74730bfb8..f576bac764613 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-use-ref-added-to-dep-without-type-info.expect.md @@ -22,13 +22,15 @@ function Foo({a}) { ## Error ``` - 3 | const ref = useRef(); - 4 | // type information is lost here as we don't track types of fields -> 5 | const val = {ref}; - | ^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5) - 6 | // without type info, we don't know that val.ref.current is a ref value so we - 7 | // *would* end up depending on val.ref.current - 8 | // however, this is an instance of accessing a ref during render and is disallowed + 8 | // however, this is an instance of accessing a ref during render and is disallowed + 9 | // under React's rules, so we reject this input +> 10 | const x = {a, val: val.ref.current}; + | ^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (10:10) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (10:10) + 11 | + 12 | return ; + 13 | } ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md deleted file mode 100644 index 866d2e2fea657..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.expect.md +++ /dev/null @@ -1,45 +0,0 @@ - -## Input - -```javascript -// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees - -import {useRef} from 'react'; - -component Foo(cond: boolean, cond2: boolean) { - const ref = useRef(); - - const s = () => { - return ref.current; - }; - - if (cond) return [s]; - else if (cond2) return {s}; - else return {s: [s]}; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Foo, - params: [{cond: false, cond2: false}], -}; - -``` - - -## Error - -``` - 10 | }; - 11 | -> 12 | if (cond) return [s]; - | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) - -InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (13:13) - -InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (14:14) - 13 | else if (cond2) return {s}; - 14 | else return {s: [s]}; - 15 | } -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md new file mode 100644 index 0000000000000..95976383cbff8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.expect.md @@ -0,0 +1,87 @@ + +## Input + +```javascript +// @flow @validateRefAccessDuringRender @validatePreserveExistingMemoizationGuarantees + +import {useRef} from 'react'; + +component Foo(cond: boolean, cond2: boolean) { + const ref = useRef(); + + const s = () => { + return ref.current; + }; + + if (cond) return [s]; + else if (cond2) return {s}; + else return {s: [s]}; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{cond: false, cond2: false}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; + +import { useRef } from "react"; + +function Foo(t0) { + const $ = _c(4); + const { cond, cond2 } = t0; + const ref = useRef(); + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t1 = () => ref.current; + $[0] = t1; + } else { + t1 = $[0]; + } + const s = t1; + if (cond) { + let t2; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + t2 = [s]; + $[1] = t2; + } else { + t2 = $[1]; + } + return t2; + } else { + if (cond2) { + let t2; + if ($[2] === Symbol.for("react.memo_cache_sentinel")) { + t2 = { s }; + $[2] = t2; + } else { + t2 = $[2]; + } + return t2; + } else { + let t2; + if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + t2 = { s: [s] }; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; + } + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ cond: false, cond2: false }], +}; + +``` + +### Eval output +(kind: ok) {"s":["[[ function params=0 ]]"]} \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.return-ref-callback-structure.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/return-ref-callback-structure.js From 5e51d767d179fda586f28e1118fb9ec5c200e35e Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:44:44 -0700 Subject: [PATCH 065/426] [compiler] Stop reusing ScopeDep type in AnalyzeFunctions AnalyzeFunctions was reusing the `ReactiveScopeDependency` type since it happened to have a convenient shape, but we need to change this type to represent optionality. We now use a locally defined type instead. ghstack-source-id: e305c6ede4bcbdffce606336c572cdc6dc1556c3 Pull Request resolved: https://github.com/facebook/react/pull/30811 --- .../src/Inference/AnalyseFunctions.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts index fbb24ea492c0f..684acaf298388 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/AnalyseFunctions.ts @@ -13,7 +13,6 @@ import { IdentifierName, LoweredFunction, Place, - ReactiveScopeDependency, isRefOrRefValue, makeInstructionId, } from '../HIR'; @@ -25,9 +24,14 @@ import {inferMutableContextVariables} from './InferMutableContextVariables'; import {inferMutableRanges} from './InferMutableRanges'; import inferReferenceEffects from './InferReferenceEffects'; +type Dependency = { + identifier: Identifier; + path: Array; +}; + // Helper class to track indirections such as LoadLocal and PropertyLoad. export class IdentifierState { - properties: Map = new Map(); + properties: Map = new Map(); resolve(identifier: Identifier): Identifier { const resolved = this.properties.get(identifier); @@ -39,7 +43,7 @@ export class IdentifierState { declareProperty(lvalue: Place, object: Place, property: string): void { const objectDependency = this.properties.get(object.identifier); - let nextDependency: ReactiveScopeDependency; + let nextDependency: Dependency; if (objectDependency === undefined) { nextDependency = {identifier: object.identifier, path: [property]}; } else { @@ -52,9 +56,7 @@ export class IdentifierState { } declareTemporary(lvalue: Place, value: Place): void { - const resolved: ReactiveScopeDependency = this.properties.get( - value.identifier, - ) ?? { + const resolved: Dependency = this.properties.get(value.identifier) ?? { identifier: value.identifier, path: [], }; From 4759161ed8d8f77bad654b6c23a063c8ad8d4864 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:52:33 -0700 Subject: [PATCH 066/426] [compiler] Wrap ReactiveScopeDep path tokens in object Previously the path of a ReactiveScopeDependency was `Array`. We need to track whether each property access is optional or not, so as a first step we change this to `Array<{property: string}>`, making space for an additional property in a subsequent PR. ghstack-source-id: c5d38d72f6b9d084a5df69ad23178794468f5f8b Pull Request resolved: https://github.com/facebook/react/pull/30812 --- .../src/HIR/HIR.ts | 12 +++- .../src/Inference/DropManualMemoization.ts | 2 +- .../ReactiveScopes/CodegenReactiveFunction.ts | 4 +- .../DeriveMinimalDependencies.ts | 70 ++++--------------- ...rgeReactiveScopesThatInvalidateTogether.ts | 5 +- .../ReactiveScopes/PrintReactiveFunction.ts | 2 +- .../PropagateScopeDependencies.ts | 27 ++----- .../PruneInitializationDependencies.ts | 4 +- .../ValidatePreservedManualMemoization.ts | 8 +-- 9 files changed, 40 insertions(+), 94 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 06fa48a73656c..e74ec52203bab 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -776,7 +776,7 @@ export type ManualMemoDependency = { value: Place; } | {kind: 'Global'; identifierName: string}; - path: Array; + path: DependencyPath; }; export type StartMemoize = { @@ -1494,9 +1494,17 @@ export type ReactiveScopeDeclaration = { export type ReactiveScopeDependency = { identifier: Identifier; - path: Array; + path: DependencyPath; }; +export function areEqualPaths(a: DependencyPath, b: DependencyPath): boolean { + return ( + a.length === b.length && + a.every((item, ix) => item.property === b[ix].property) + ); +} +export type DependencyPath = Array<{property: string}>; + /* * Simulated opaque type for BlockIds to prevent using normal numbers as block ids * accidentally. diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index c9d2a7e1412c3..e60d8a9914583 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -68,7 +68,7 @@ export function collectMaybeMemoDependencies( if (object != null) { return { root: object.root, - path: [...object.path, value.property], + path: [...object.path, {property: value.property}], }; } break; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index 624a4b604d66f..73330b959e018 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -1411,7 +1411,7 @@ function printDependencyComment(dependency: ReactiveScopeDependency): string { let name = identifier.name; if (dependency.path !== null) { for (const path of dependency.path) { - name += `.${path}`; + name += `.${path.property}`; } } return name; @@ -1448,7 +1448,7 @@ function codegenDependency( let object: t.Expression = convertIdentifier(dependency.identifier); if (dependency.path !== null) { for (const path of dependency.path) { - object = t.memberExpression(object, t.identifier(path)); + object = t.memberExpression(object, t.identifier(path.property)); } } return object; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts index 8c2e31fa9666e..13420ee140e63 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts @@ -14,20 +14,8 @@ import {assertExhaustive} from '../Utils/utils'; * We need to understand optional member expressions only when determining * dependencies of a ReactiveScope (i.e. in {@link PropagateScopeDependencies}), * hence why this type lives here (not in HIR.ts) - * - * {@link ReactiveScopePropertyDependency.optionalPath} is populated only if the Property - * represents an optional member expression, and it represents the property path - * loaded conditionally. - * e.g. the member expr a.b.c?.d.e?.f is represented as - * { - * identifier: 'a'; - * path: ['b', 'c'], - * optionalPath: ['d', 'e', 'f']. - * } */ -export type ReactiveScopePropertyDependency = ReactiveScopeDependency & { - optionalPath: Array; -}; +export type ReactiveScopePropertyDependency = ReactiveScopeDependency; /* * Finalizes a set of ReactiveScopeDependencies to produce a set of minimal unconditional @@ -69,59 +57,29 @@ export class ReactiveScopeDependencyTree { } add(dep: ReactiveScopePropertyDependency, inConditional: boolean): void { - const {path, optionalPath} = dep; + const {path} = dep; let currNode = this.#getOrCreateRoot(dep.identifier); const accessType = inConditional ? PropertyAccessType.ConditionalAccess : PropertyAccessType.UnconditionalAccess; - for (const property of path) { + for (const item of path) { // all properties read 'on the way' to a dependency are marked as 'access' - let currChild = getOrMakeProperty(currNode, property); + let currChild = getOrMakeProperty(currNode, item.property); currChild.accessType = merge(currChild.accessType, accessType); currNode = currChild; } - if (optionalPath.length === 0) { - /* - * If this property does not have a conditional path (i.e. a.b.c), the - * final property node should be marked as an conditional/unconditional - * `dependency` as based on control flow. - */ - const depType = inConditional - ? PropertyAccessType.ConditionalDependency - : PropertyAccessType.UnconditionalDependency; - - currNode.accessType = merge(currNode.accessType, depType); - } else { - /* - * Technically, we only depend on whether unconditional path `dep.path` - * is nullish (not its actual value). As long as we preserve the nullthrows - * behavior of `dep.path`, we can keep it as an access (and not promote - * to a dependency). - * See test `reduce-reactive-cond-memberexpr-join` for example. - */ - - /* - * If this property has an optional path (i.e. a?.b.c), all optional - * nodes should be marked accordingly. - */ - for (const property of optionalPath) { - let currChild = getOrMakeProperty(currNode, property); - currChild.accessType = merge( - currChild.accessType, - PropertyAccessType.ConditionalAccess, - ); - currNode = currChild; - } + /** + * The final property node should be marked as an conditional/unconditional + * `dependency` as based on control flow. + */ + const depType = inConditional + ? PropertyAccessType.ConditionalDependency + : PropertyAccessType.UnconditionalDependency; - // The final node should be marked as a conditional dependency. - currNode.accessType = merge( - currNode.accessType, - PropertyAccessType.ConditionalDependency, - ); - } + currNode.accessType = merge(currNode.accessType, depType); } deriveMinimalDependencies(): Set { @@ -294,7 +252,7 @@ type DependencyNode = { }; type ReduceResultNode = { - relativePath: Array; + relativePath: Array<{property: string}>; accessType: PropertyAccessType; }; @@ -325,7 +283,7 @@ function deriveMinimalDependenciesInSubtree( const childResult = deriveMinimalDependenciesInSubtree(childNode).map( ({relativePath, accessType}) => { return { - relativePath: [childName, ...relativePath], + relativePath: [{property: childName}, ...relativePath], accessType, }; }, diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts index 1e73697783f0b..08d2212d86b95 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts @@ -19,6 +19,7 @@ import { ReactiveScopeDependency, ReactiveStatement, Type, + areEqualPaths, makeInstructionId, } from '../HIR'; import { @@ -525,10 +526,6 @@ function areEqualDependencies( return true; } -export function areEqualPaths(a: Array, b: Array): boolean { - return a.length === b.length && a.every((item, ix) => item === b[ix]); -} - /** * Is this scope eligible for merging with subsequent scopes? In general this * is only true if the scope's output values are guaranteed to change when its diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts index f85f7071f1c49..80395a2e0ea41 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts @@ -113,7 +113,7 @@ export function printDependency(dependency: ReactiveScopeDependency): string { const identifier = printIdentifier(dependency.identifier) + printType(dependency.identifier.type); - return `${identifier}${dependency.path.map(prop => `.${prop}`).join('')}`; + return `${identifier}${dependency.path.map(token => `.${token.property}`).join('')}`; } export function printReactiveInstructions( diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts index 690bdb758839d..0e47a8dcedfb2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -7,6 +7,7 @@ import {CompilerError} from '../CompilerError'; import { + areEqualPaths, BlockId, DeclarationId, GeneratedSource, @@ -35,7 +36,6 @@ import { ReactiveScopeDependencyTree, ReactiveScopePropertyDependency, } from './DeriveMinimalDependencies'; -import {areEqualPaths} from './MergeReactiveScopesThatInvalidateTogether'; import {ReactiveFunctionVisitor, visitReactiveFunction} from './visitors'; /* @@ -465,7 +465,6 @@ class Context { #getProperty( object: Place, property: string, - isConditional: boolean, ): ReactiveScopePropertyDependency { const resolvedObject = this.resolveTemporary(object); const resolvedDependency = this.#properties.get(resolvedObject.identifier); @@ -478,36 +477,21 @@ class Context { objectDependency = { identifier: resolvedObject.identifier, path: [], - optionalPath: [], }; } else { objectDependency = { identifier: resolvedDependency.identifier, path: [...resolvedDependency.path], - optionalPath: [...resolvedDependency.optionalPath], }; } - // (2) Determine whether property is an optional access - if (objectDependency.optionalPath.length > 0) { - /* - * If the base property dependency represents a optional member expression, - * property is on the optionalPath (regardless of whether this PropertyLoad - * itself was conditional) - * e.g. for `a.b?.c.d`, `d` should be added to optionalPath - */ - objectDependency.optionalPath.push(property); - } else if (isConditional) { - objectDependency.optionalPath.push(property); - } else { - objectDependency.path.push(property); - } + objectDependency.path.push({property}); return objectDependency; } declareProperty(lvalue: Place, object: Place, property: string): void { - const nextDependency = this.#getProperty(object, property, false); + const nextDependency = this.#getProperty(object, property); this.#properties.set(lvalue.identifier, nextDependency); } @@ -516,7 +500,7 @@ class Context { // ref.current access is not a valid dep if ( isUseRefType(maybeDependency.identifier) && - maybeDependency.path.at(0) === 'current' + maybeDependency.path.at(0)?.property === 'current' ) { return false; } @@ -577,7 +561,6 @@ class Context { let dependency: ReactiveScopePropertyDependency = { identifier: resolved.identifier, path: [], - optionalPath: [], }; if (resolved.identifier.name === null) { const propertyDependency = this.#properties.get(resolved.identifier); @@ -589,7 +572,7 @@ class Context { } visitProperty(object: Place, property: string): void { - const nextDependency = this.#getProperty(object, property, false); + const nextDependency = this.#getProperty(object, property); this.visitDependency(nextDependency); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts index 721fa7b0ec65d..2a9d0b9793d9f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneInitializationDependencies.ts @@ -180,8 +180,8 @@ class Visitor extends ReactiveFunctionVisitor { [...scope.scope.dependencies].forEach(ident => { let target: undefined | IdentifierId = this.aliases.find(ident.identifier.id) ?? ident.identifier.id; - ident.path.forEach(key => { - target &&= this.paths.get(target)?.get(key); + ident.path.forEach(token => { + target &&= this.paths.get(target)?.get(token.property); }); if (target && this.map.get(target) === 'Create') { scope.scope.dependencies.delete(ident); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 7af4aaaccd7ab..43a477f3418e6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -167,7 +167,7 @@ function compareDeps( let isSubpath = true; for (let i = 0; i < Math.min(inferred.path.length, source.path.length); i++) { - if (inferred.path[i] !== source.path[i]) { + if (inferred.path[i].property !== source.path[i].property) { isSubpath = false; break; } @@ -177,14 +177,14 @@ function compareDeps( isSubpath && (source.path.length === inferred.path.length || (inferred.path.length >= source.path.length && - !inferred.path.includes('current'))) + !inferred.path.some(token => token.property === 'current'))) ) { return CompareDependencyResult.Ok; } else { if (isSubpath) { if ( - source.path.includes('current') || - inferred.path.includes('current') + source.path.some(token => token.property === 'current') || + inferred.path.some(token => token.property === 'current') ) { return CompareDependencyResult.RefAccessDifference; } else { From a718da0b23c3f72ba6fb8e1bd087aca85f2b0b4a Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:52:33 -0700 Subject: [PATCH 067/426] [compiler] Add DependencyPath optional property Adds an `optional: boolean` property to each token in a DependencyPath, currently always set to false. Also updates the equality and printing logic for paths to account for this field. Subsequent PRs will update our logic to determine which manual dependencies were optional, then we can start inferring optional deps as well. ghstack-source-id: 66c2da2cfab5e5ba6c2ac5e20adae5e4f615ad29 Pull Request resolved: https://github.com/facebook/react/pull/30813 --- .../src/HIR/HIR.ts | 7 ++-- .../src/HIR/PrintHIR.ts | 2 +- .../src/Inference/DropManualMemoization.ts | 3 +- .../DeriveMinimalDependencies.ts | 9 ++++-- .../PropagateScopeDependencies.ts | 2 +- .../ValidatePreservedManualMemoization.ts | 2 +- ...al-member-expression-as-memo-dep.expect.md | 32 +++++++++++++++++++ ...-optional-member-expression-as-memo-dep.js | 7 ++++ 8 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index e74ec52203bab..3bc7b135b6ced 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -1500,10 +1500,13 @@ export type ReactiveScopeDependency = { export function areEqualPaths(a: DependencyPath, b: DependencyPath): boolean { return ( a.length === b.length && - a.every((item, ix) => item.property === b[ix].property) + a.every( + (item, ix) => + item.property === b[ix].property && item.optional === b[ix].optional, + ) ); } -export type DependencyPath = Array<{property: string}>; +export type DependencyPath = Array<{property: string; optional: boolean}>; /* * Simulated opaque type for BlockIds to prevent using normal numbers as block ids diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index 8bcab1d7b25ae..ecf0b5f0c6041 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -869,7 +869,7 @@ export function printManualMemoDependency( ? val.root.value.identifier.name.value : printIdentifier(val.root.value.identifier); } - return `${rootStr}${val.path.length > 0 ? '.' : ''}${val.path.join('.')}`; + return `${rootStr}${val.path.map(v => `${v.optional ? '?.' : '.'}${v.property}`).join('')}`; } export function printType(type: Type): string { if (type.kind === 'Type') return ''; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index e60d8a9914583..c580b3e8b759f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -68,7 +68,8 @@ export function collectMaybeMemoDependencies( if (object != null) { return { root: object.root, - path: [...object.path, {property: value.property}], + // TODO: determine if the access is optional + path: [...object.path, {property: value.property, optional: false}], }; } break; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts index 13420ee140e63..dcf67a36e5c6b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts @@ -6,7 +6,7 @@ */ import {CompilerError} from '../CompilerError'; -import {Identifier, ReactiveScopeDependency} from '../HIR'; +import {DependencyPath, Identifier, ReactiveScopeDependency} from '../HIR'; import {printIdentifier} from '../HIR/PrintHIR'; import {assertExhaustive} from '../Utils/utils'; @@ -252,7 +252,7 @@ type DependencyNode = { }; type ReduceResultNode = { - relativePath: Array<{property: string}>; + relativePath: DependencyPath; accessType: PropertyAccessType; }; @@ -283,7 +283,10 @@ function deriveMinimalDependenciesInSubtree( const childResult = deriveMinimalDependenciesInSubtree(childNode).map( ({relativePath, accessType}) => { return { - relativePath: [{property: childName}, ...relativePath], + relativePath: [ + {property: childName, optional: false}, + ...relativePath, + ], accessType, }; }, diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts index 0e47a8dcedfb2..8fd324ae2c9aa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -485,7 +485,7 @@ class Context { }; } - objectDependency.path.push({property}); + objectDependency.path.push({property, optional: false}); return objectDependency; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 43a477f3418e6..5a9a947d88bfd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -116,7 +116,7 @@ function prettyPrintScopeDependency(val: ReactiveScopeDependency): string { } else { rootStr = '[unnamed]'; } - return `${rootStr}${val.path.length > 0 ? '.' : ''}${val.path.join('.')}`; + return `${rootStr}${val.path.map(v => `${v.optional ? '?.' : '.'}${v.property}`).join('')}`; } enum CompareDependencyResult { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md new file mode 100644 index 0000000000000..7e4145a27c16b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md @@ -0,0 +1,32 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +function Component(props) { + const data = useMemo(() => { + return props.items?.edges?.nodes ?? []; + }, [props.items?.edges?.nodes]); + return ; +} + +``` + + +## Error + +``` + 1 | // @validatePreserveExistingMemoizationGuarantees + 2 | function Component(props) { +> 3 | const data = useMemo(() => { + | ^^^^^^^ +> 4 | return props.items?.edges?.nodes ?? []; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 5 | }, [props.items?.edges?.nodes]); + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (3:5) + 6 | return ; + 7 | } + 8 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js new file mode 100644 index 0000000000000..fd8cf0214c87b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js @@ -0,0 +1,7 @@ +// @validatePreserveExistingMemoizationGuarantees +function Component(props) { + const data = useMemo(() => { + return props.items?.edges?.nodes ?? []; + }, [props.items?.edges?.nodes]); + return ; +} From 925c20a20674254391b7752aa216ec417c8f52a3 Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:52:34 -0700 Subject: [PATCH 068/426] [compiler] Add fallthrough to branch terminal Branch terminals didn't have a fallthrough because they correspond to an outer terminal (optional, logical, etc) that has the "real" fallthrough. But understanding how branch terminals correspond to these outer terminals requires knowing the branch fallthrough. For example, `foo?.bar?.baz` creates terminals along the lines of: ``` bb0: optional fallthrough=bb4 bb1: optional fallthrough=bb3 bb2: ... branch ... (fallthrough=bb3) ... bb3: ... branch ... (fallthrough=bb4) ... bb4: ... ``` Without a fallthrough on `branch` terminals, it's unclear that the optional from bb0 has its branch node in bb3. With the fallthroughs, we can see look for a branch with the same fallthrough as the outer optional terminal to match them up. ghstack-source-id: d48c6232899864716eef71798a278b487d30eafc Pull Request resolved: https://github.com/facebook/react/pull/30814 --- .../src/HIR/BuildHIR.ts | 14 +++-- .../src/HIR/HIR.ts | 2 +- .../src/HIR/visitors.ts | 4 +- .../src/Inference/DropManualMemoization.ts | 55 ++++++++++++++++++- .../AlignReactiveScopesToBlockScopesHIR.ts | 2 +- .../ValidatePreservedManualMemoization.ts | 11 +++- 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 06fcfbea7ecc0..7fb12d4624c10 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -607,6 +607,7 @@ function lowerStatement( ), consequent: bodyBlock, alternate: continuationBlock.id, + fallthrough: continuationBlock.id, id: makeInstructionId(0), loc: stmt.node.loc ?? GeneratedSource, }, @@ -656,16 +657,13 @@ function lowerStatement( }, conditionalBlock, ); - /* - * The conditional block is empty and exists solely as conditional for - * (re)entering or exiting the loop - */ const test = lowerExpressionToTemporary(builder, stmt.get('test')); const terminal: BranchTerminal = { kind: 'branch', test, consequent: loopBlock, alternate: continuationBlock.id, + fallthrough: conditionalBlock.id, id: makeInstructionId(0), loc: stmt.node.loc ?? GeneratedSource, }; @@ -975,6 +973,7 @@ function lowerStatement( test, consequent: loopBlock, alternate: continuationBlock.id, + fallthrough: conditionalBlock.id, id: makeInstructionId(0), loc, }; @@ -1118,6 +1117,7 @@ function lowerStatement( consequent: loopBlock, alternate: continuationBlock.id, loc: stmt.node.loc ?? GeneratedSource, + fallthrough: continuationBlock.id, }, continuationBlock, ); @@ -1203,6 +1203,7 @@ function lowerStatement( test, consequent: loopBlock, alternate: continuationBlock.id, + fallthrough: continuationBlock.id, loc: stmt.node.loc ?? GeneratedSource, }, continuationBlock, @@ -1800,6 +1801,7 @@ function lowerExpression( test: {...testPlace}, consequent: consequentBlock, alternate: alternateBlock, + fallthrough: continuationBlock.id, id: makeInstructionId(0), loc: exprLoc, }, @@ -1878,6 +1880,7 @@ function lowerExpression( test: {...leftPlace}, consequent, alternate, + fallthrough: continuationBlock.id, id: makeInstructionId(0), loc: exprLoc, }, @@ -2611,6 +2614,7 @@ function lowerOptionalMemberExpression( test: {...object}, consequent: consequent.id, alternate, + fallthrough: continuationBlock.id, id: makeInstructionId(0), loc, }; @@ -2750,6 +2754,7 @@ function lowerOptionalCallExpression( test: {...testPlace}, consequent: consequent.id, alternate, + fallthrough: continuationBlock.id, id: makeInstructionId(0), loc, }; @@ -4025,6 +4030,7 @@ function lowerAssignment( test: {...test}, consequent, alternate, + fallthrough: continuationBlock.id, id: makeInstructionId(0), loc, }, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 3bc7b135b6ced..3a04a4c3c9dce 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -491,7 +491,7 @@ export type BranchTerminal = { alternate: BlockId; id: InstructionId; loc: SourceLocation; - fallthrough?: never; + fallthrough: BlockId; }; export type SwitchTerminal = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts index 0df8478b39c45..904b7a4038dec 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts @@ -660,11 +660,13 @@ export function mapTerminalSuccessors( case 'branch': { const consequent = fn(terminal.consequent); const alternate = fn(terminal.alternate); + const fallthrough = fn(terminal.fallthrough); return { kind: 'branch', test: terminal.test, consequent, alternate, + fallthrough, id: makeInstructionId(0), loc: terminal.loc, }; @@ -883,7 +885,6 @@ export function terminalHasFallthrough< >(terminal: T): terminal is U { switch (terminal.kind) { case 'maybe-throw': - case 'branch': case 'goto': case 'return': case 'throw': @@ -892,6 +893,7 @@ export function terminalHasFallthrough< const _: undefined = terminal.fallthrough; return false; } + case 'branch': case 'try': case 'do-while': case 'for-of': diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index c580b3e8b759f..fdd9bcc968aef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -42,6 +42,7 @@ type IdentifierSidemap = { react: Set; maybeDepsLists: Map>; maybeDeps: Map; + optionals: Set; }; /** @@ -52,6 +53,7 @@ type IdentifierSidemap = { export function collectMaybeMemoDependencies( value: InstructionValue, maybeDeps: Map, + optional: boolean, ): ManualMemoDependency | null { switch (value.kind) { case 'LoadGlobal': { @@ -69,7 +71,7 @@ export function collectMaybeMemoDependencies( return { root: object.root, // TODO: determine if the access is optional - path: [...object.path, {property: value.property, optional: false}], + path: [...object.path, {property: value.property, optional}], }; } break; @@ -162,7 +164,11 @@ function collectTemporaries( break; } } - const maybeDep = collectMaybeMemoDependencies(value, sidemap.maybeDeps); + const maybeDep = collectMaybeMemoDependencies( + value, + sidemap.maybeDeps, + sidemap.optionals.has(lvalue.identifier.id), + ); // We don't expect named lvalues during this pass (unlike ValidatePreservingManualMemo) if (maybeDep != null) { sidemap.maybeDeps.set(lvalue.identifier.id, maybeDep); @@ -338,12 +344,14 @@ export function dropManualMemoization(func: HIRFunction): void { func.env.config.validatePreserveExistingMemoizationGuarantees || func.env.config.validateNoSetStateInRender || func.env.config.enablePreserveExistingMemoizationGuarantees; + const optionals = findOptionalPlaces(func); const sidemap: IdentifierSidemap = { functions: new Map(), manualMemos: new Map(), react: new Set(), maybeDeps: new Map(), maybeDepsLists: new Map(), + optionals, }; let nextManualMemoId = 0; @@ -476,3 +484,46 @@ export function dropManualMemoization(func: HIRFunction): void { } } } + +function findOptionalPlaces(fn: HIRFunction): Set { + const optionals = new Set(); + for (const [, block] of fn.body.blocks) { + if (block.terminal.kind === 'optional') { + const optionalTerminal = block.terminal; + let testBlock = fn.body.blocks.get(block.terminal.test)!; + loop: while (true) { + const terminal = testBlock.terminal; + switch (terminal.kind) { + case 'branch': { + if (terminal.fallthrough === optionalTerminal.fallthrough) { + // found it + const consequent = fn.body.blocks.get(terminal.consequent)!; + const last = consequent.instructions.at(-1); + if (last !== undefined && last.value.kind === 'StoreLocal') { + optionals.add(last.value.value.identifier.id); + } + break loop; + } else { + testBlock = fn.body.blocks.get(terminal.fallthrough)!; + } + break; + } + case 'optional': + case 'logical': + case 'sequence': + case 'ternary': { + testBlock = fn.body.blocks.get(terminal.fallthrough)!; + break; + } + default: { + CompilerError.invariant(false, { + reason: `Unexpected terminal in optional`, + loc: terminal.loc, + }); + } + } + } + } + } + return optionals; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts index 6517918d02e16..3e8329679cfe2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/AlignReactiveScopesToBlockScopesHIR.ts @@ -140,7 +140,7 @@ export function alignReactiveScopesToBlockScopesHIR(fn: HIRFunction): void { } const fallthrough = terminalFallthrough(terminal); - if (fallthrough !== null) { + if (fallthrough !== null && terminal.kind !== 'branch') { /* * Any currently active scopes that overlaps the block-fallthrough range * need their range extended to at least the first instruction of the diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 5a9a947d88bfd..6d948fad9711a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -167,7 +167,10 @@ function compareDeps( let isSubpath = true; for (let i = 0; i < Math.min(inferred.path.length, source.path.length); i++) { - if (inferred.path[i].property !== source.path[i].property) { + if ( + inferred.path[i].property !== source.path[i].property || + inferred.path[i].optional !== source.path[i].optional + ) { isSubpath = false; break; } @@ -339,7 +342,11 @@ class Visitor extends ReactiveFunctionVisitor { return null; } default: { - const dep = collectMaybeMemoDependencies(value, this.temporaries); + const dep = collectMaybeMemoDependencies( + value, + this.temporaries, + false, + ); if (value.kind === 'StoreLocal' || value.kind === 'StoreContext') { const storeTarget = value.lvalue.place; state.manualMemoState?.decls.add( From 9180a37fba0c9ad642bfc6e1c2839f88f66485ab Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:52:35 -0700 Subject: [PATCH 069/426] [compiler] Allow inferred non-optional paths when manual deps were optional If the inferred deps are more precise (non-optional) than the manual deps (optional) it should pass validation. The other direction also seems like it would be fine - inferring optional deps when the original was non-optional - but for now let's keep the "at least as precise" rule. ghstack-source-id: 9f7a99ee5f7caa2c2d96f70f360e4320bac3de2d Pull Request resolved: https://github.com/facebook/react/pull/30816 --- .../ValidatePreservedManualMemoization.ts | 12 +++-- ...as-memo-dep-non-optional-in-body.expect.md | 50 +++++++++++++++++++ ...ession-as-memo-dep-non-optional-in-body.js | 9 ++++ 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 6d948fad9711a..4f0c756585cf0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -167,12 +167,16 @@ function compareDeps( let isSubpath = true; for (let i = 0; i < Math.min(inferred.path.length, source.path.length); i++) { - if ( - inferred.path[i].property !== source.path[i].property || - inferred.path[i].optional !== source.path[i].optional - ) { + if (inferred.path[i].property !== source.path[i].property) { isSubpath = false; break; + } else if (inferred.path[i].optional && !source.path[i].optional) { + /** + * The inferred path must be at least as precise as the manual path: + * if the inferred path is optional, then the source path must have + * been optional too. + */ + return CompareDependencyResult.PathDifference; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md new file mode 100644 index 0000000000000..7cf1bcd90b339 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +function Component(props) { + const data = useMemo(() => { + // actual code is non-optional + return props.items.edges.nodes ?? []; + // deps are optional + }, [props.items?.edges?.nodes]); + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees +function Component(props) { + const $ = _c(4); + + props.items?.edges?.nodes; + let t0; + let t1; + if ($[0] !== props.items.edges.nodes) { + t1 = props.items.edges.nodes ?? []; + $[0] = props.items.edges.nodes; + $[1] = t1; + } else { + t1 = $[1]; + } + t0 = t1; + const data = t0; + let t2; + if ($[2] !== data) { + t2 = ; + $[2] = data; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.js new file mode 100644 index 0000000000000..1a6196a494e66 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.js @@ -0,0 +1,9 @@ +// @validatePreserveExistingMemoizationGuarantees +function Component(props) { + const data = useMemo(() => { + // actual code is non-optional + return props.items.edges.nodes ?? []; + // deps are optional + }, [props.items?.edges?.nodes]); + return ; +} From 7475d568da137b661ce23edc24446871d58c67ef Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:52:36 -0700 Subject: [PATCH 070/426] [wip][compiler] Infer optional dependencies Updates PropagateScopeDeps and DeriveMinimalDeps to understand optional dependency paths (`a?.b`). There a few key pieces to this: In PropagateScopeDeps we jump through some hoops to work around the awkward structure of nested OptionalExpressions. This is much easier in HIR form, but I managed to get this pretty close and i think it will be landable with further cleanup. A good chunk of this is avoiding prematurely registering a value as a dependency - there are a bunch of indirections in the ReactiveFunction structure: ``` t0 = OptionalExpression SequenceExpression t0 = Sequence ... LoadLocal t0 ``` Where if at any point we call `visitOperand()` we'll prematurely register a dependency instead of declareProperty(). The other bit is that optionals can be optional=false for nested member expressions where not all the parts are actually optional (`foo.bar?.bar.call()`). And of course, parts of an optional chain can still be conditional even when optional=true (for example the `x` in `foo.bar?.[x]?.baz`). Not all of this is tested yet so there are likely bugs still. The other bit is DeriveMinimalDeps, which is thankfully easier. We add OptionalAccess and OptionalDep and update the merge and reducing logic for these cases. There is probably still more to update though, for things like merging subtrees. There are a lot of ternaries that assume a result can be exactly one of two states (conditional/unconditional, dependency/access) and these assumptions don't hold anymore. I'd like to refactor to dependency/access separate from conditional/optional/unconditional. Also, the reducing logic isn't quite right: once a child is optional we keep inferring all the parents as optional too, losing some precision. I need to adjust the reducing logic to let children decide whether their path token is optional or not. ghstack-source-id: 207842ac64560cf0f93ec96eb9ae1f17c62493ac Pull Request resolved: https://github.com/facebook/react/pull/30819 --- .../src/HIR/Environment.ts | 8 + .../src/HIR/PrintHIR.ts | 2 +- .../ReactiveScopes/CodegenReactiveFunction.ts | 14 +- .../DeriveMinimalDependencies.ts | 165 ++++++++--- .../ReactiveScopes/PrintReactiveFunction.ts | 2 +- .../PropagateScopeDependencies.ts | 271 ++++++++++++++---- ...al-member-expression-as-memo-dep.expect.md | 32 --- ...-optional-member-expression-as-memo-dep.js | 7 - ...al-member-expression-as-memo-dep.expect.md | 48 ++++ .../optional-member-expression-as-memo-dep.js | 7 + ...ession-single-with-unconditional.expect.md | 65 +++++ ...er-expression-single-with-unconditional.js | 11 + ...ptional-member-expression-single.expect.md | 63 ++++ .../optional-member-expression-single.js | 10 + ...ession-with-conditional-optional.expect.md | 74 +++++ ...er-expression-with-conditional-optional.js | 15 + ...mber-expression-with-conditional.expect.md | 74 +++++ ...onal-member-expression-with-conditional.js | 15 + 18 files changed, 755 insertions(+), 128 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 12c741641c7e0..a13ebb6aac878 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -224,6 +224,14 @@ const EnvironmentConfigSchema = z.object({ enableReactiveScopesInHIR: z.boolean().default(true), + /** + * Enables inference of optional dependency chains. Without this flag + * a property chain such as `props?.items?.foo` will infer as a dep on + * just `props`. With this flag enabled, we'll infer that full path as + * the dependency. + */ + enableOptionalDependencies: z.boolean().default(false), + /* * Enable validation of hooks to partially check that the component honors the rules of hooks. * When disabled, the component is assumed to follow the rules (though the Babel plugin looks diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index ecf0b5f0c6041..c2db20c5099a1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -191,7 +191,7 @@ export function printTerminal(terminal: Terminal): Array | string { case 'branch': { value = `[${terminal.id}] Branch (${printPlace(terminal.test)}) then:bb${ terminal.consequent - } else:bb${terminal.alternate}`; + } else:bb${terminal.alternate} fallthrough:bb${terminal.fallthrough}`; break; } case 'logical': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index 73330b959e018..2df7b5ed1c7fd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -1446,9 +1446,19 @@ function codegenDependency( dependency: ReactiveScopeDependency, ): t.Expression { let object: t.Expression = convertIdentifier(dependency.identifier); - if (dependency.path !== null) { + if (dependency.path.length !== 0) { + const hasOptional = dependency.path.some(path => path.optional); for (const path of dependency.path) { - object = t.memberExpression(object, t.identifier(path.property)); + if (hasOptional) { + object = t.optionalMemberExpression( + object, + t.identifier(path.property), + false, + path.optional, + ); + } else { + object = t.memberExpression(object, t.identifier(path.property)); + } } } return object; diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts index dcf67a36e5c6b..c7e16cce7ac86 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/DeriveMinimalDependencies.ts @@ -60,13 +60,14 @@ export class ReactiveScopeDependencyTree { const {path} = dep; let currNode = this.#getOrCreateRoot(dep.identifier); - const accessType = inConditional - ? PropertyAccessType.ConditionalAccess - : PropertyAccessType.UnconditionalAccess; - for (const item of path) { // all properties read 'on the way' to a dependency are marked as 'access' let currChild = getOrMakeProperty(currNode, item.property); + const accessType = inConditional + ? PropertyAccessType.ConditionalAccess + : item.optional + ? PropertyAccessType.OptionalAccess + : PropertyAccessType.UnconditionalAccess; currChild.accessType = merge(currChild.accessType, accessType); currNode = currChild; } @@ -77,7 +78,9 @@ export class ReactiveScopeDependencyTree { */ const depType = inConditional ? PropertyAccessType.ConditionalDependency - : PropertyAccessType.UnconditionalDependency; + : isOptional(currNode.accessType) + ? PropertyAccessType.OptionalDependency + : PropertyAccessType.UnconditionalDependency; currNode.accessType = merge(currNode.accessType, depType); } @@ -85,10 +88,12 @@ export class ReactiveScopeDependencyTree { deriveMinimalDependencies(): Set { const results = new Set(); for (const [rootId, rootNode] of this.#roots.entries()) { - const deps = deriveMinimalDependenciesInSubtree(rootNode); + const deps = deriveMinimalDependenciesInSubtree(rootNode, null); CompilerError.invariant( deps.every( - dep => dep.accessType === PropertyAccessType.UnconditionalDependency, + dep => + dep.accessType === PropertyAccessType.UnconditionalDependency || + dep.accessType == PropertyAccessType.OptionalDependency, ), { reason: @@ -173,6 +178,27 @@ export class ReactiveScopeDependencyTree { } return res.flat().join('\n'); } + + debug(): string { + const buf: Array = [`tree() [`]; + for (const [rootId, rootNode] of this.#roots) { + buf.push(`${printIdentifier(rootId)} (${rootNode.accessType}):`); + this.#debugImpl(buf, rootNode, 1); + } + buf.push(']'); + return buf.length > 2 ? buf.join('\n') : buf.join(''); + } + + #debugImpl( + buf: Array, + node: DependencyNode, + depth: number = 0, + ): void { + for (const [property, childNode] of node.properties) { + buf.push(`${' '.repeat(depth)}.${property} (${childNode.accessType}):`); + this.#debugImpl(buf, childNode, depth + 1); + } + } } /* @@ -196,8 +222,10 @@ export class ReactiveScopeDependencyTree { */ enum PropertyAccessType { ConditionalAccess = 'ConditionalAccess', + OptionalAccess = 'OptionalAccess', UnconditionalAccess = 'UnconditionalAccess', ConditionalDependency = 'ConditionalDependency', + OptionalDependency = 'OptionalDependency', UnconditionalDependency = 'UnconditionalDependency', } @@ -211,9 +239,16 @@ function isUnconditional(access: PropertyAccessType): boolean { function isDependency(access: PropertyAccessType): boolean { return ( access === PropertyAccessType.ConditionalDependency || + access === PropertyAccessType.OptionalDependency || access === PropertyAccessType.UnconditionalDependency ); } +function isOptional(access: PropertyAccessType): boolean { + return ( + access === PropertyAccessType.OptionalAccess || + access === PropertyAccessType.OptionalDependency + ); +} function merge( access1: PropertyAccessType, @@ -222,6 +257,7 @@ function merge( const resultIsUnconditional = isUnconditional(access1) || isUnconditional(access2); const resultIsDependency = isDependency(access1) || isDependency(access2); + const resultIsOptional = isOptional(access1) || isOptional(access2); /* * Straightforward merge. @@ -237,6 +273,12 @@ function merge( } else { return PropertyAccessType.UnconditionalAccess; } + } else if (resultIsOptional) { + if (resultIsDependency) { + return PropertyAccessType.OptionalDependency; + } else { + return PropertyAccessType.OptionalAccess; + } } else { if (resultIsDependency) { return PropertyAccessType.ConditionalDependency; @@ -256,19 +298,34 @@ type ReduceResultNode = { accessType: PropertyAccessType; }; -const promoteUncondResult = [ - { +function promoteResult( + accessType: PropertyAccessType, + path: {property: string; optional: boolean} | null, +): Array { + const result: ReduceResultNode = { relativePath: [], - accessType: PropertyAccessType.UnconditionalDependency, - }, -]; + accessType, + }; + if (path !== null) { + result.relativePath.push(path); + } + return [result]; +} -const promoteCondResult = [ - { - relativePath: [], - accessType: PropertyAccessType.ConditionalDependency, - }, -]; +function prependPath( + results: Array, + path: {property: string; optional: boolean} | null, +): Array { + if (path === null) { + return results; + } + return results.map(result => { + return { + accessType: result.accessType, + relativePath: [path, ...result.relativePath], + }; + }); +} /* * Recursively calculates minimal dependencies in a subtree. @@ -277,42 +334,76 @@ const promoteCondResult = [ */ function deriveMinimalDependenciesInSubtree( dep: DependencyNode, + property: string | null, ): Array { const results: Array = []; for (const [childName, childNode] of dep.properties) { - const childResult = deriveMinimalDependenciesInSubtree(childNode).map( - ({relativePath, accessType}) => { - return { - relativePath: [ - {property: childName, optional: false}, - ...relativePath, - ], - accessType, - }; - }, + const childResult = deriveMinimalDependenciesInSubtree( + childNode, + childName, ); results.push(...childResult); } switch (dep.accessType) { case PropertyAccessType.UnconditionalDependency: { - return promoteUncondResult; + return promoteResult( + PropertyAccessType.UnconditionalDependency, + property !== null ? {property, optional: false} : null, + ); } case PropertyAccessType.UnconditionalAccess: { if ( results.every( ({accessType}) => - accessType === PropertyAccessType.UnconditionalDependency, + accessType === PropertyAccessType.UnconditionalDependency || + accessType === PropertyAccessType.OptionalDependency, ) ) { // all children are unconditional dependencies, return them to preserve granularity - return results; + return prependPath( + results, + property !== null ? {property, optional: false} : null, + ); } else { /* * at least one child is accessed conditionally, so this node needs to be promoted to * unconditional dependency */ - return promoteUncondResult; + return promoteResult( + PropertyAccessType.UnconditionalDependency, + property !== null ? {property, optional: false} : null, + ); + } + } + case PropertyAccessType.OptionalDependency: { + return promoteResult( + PropertyAccessType.OptionalDependency, + property !== null ? {property, optional: true} : null, + ); + } + case PropertyAccessType.OptionalAccess: { + if ( + results.every( + ({accessType}) => + accessType === PropertyAccessType.UnconditionalDependency || + accessType === PropertyAccessType.OptionalDependency, + ) + ) { + // all children are unconditional dependencies, return them to preserve granularity + return prependPath( + results, + property !== null ? {property, optional: true} : null, + ); + } else { + /* + * at least one child is accessed conditionally, so this node needs to be promoted to + * unconditional dependency + */ + return promoteResult( + PropertyAccessType.OptionalDependency, + property !== null ? {property, optional: true} : null, + ); } } case PropertyAccessType.ConditionalAccess: @@ -328,13 +419,19 @@ function deriveMinimalDependenciesInSubtree( * unconditional access. * Truncate results of child nodes here, since we shouldn't access them anyways */ - return promoteCondResult; + return promoteResult( + PropertyAccessType.ConditionalDependency, + property !== null ? {property, optional: true} : null, + ); } else { /* * at least one child is accessed unconditionally, so this node can be promoted to * unconditional dependency */ - return promoteUncondResult; + return promoteResult( + PropertyAccessType.UnconditionalDependency, + property !== null ? {property, optional: true} : null, + ); } } default: { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts index 80395a2e0ea41..b5aa44ead095d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PrintReactiveFunction.ts @@ -113,7 +113,7 @@ export function printDependency(dependency: ReactiveScopeDependency): string { const identifier = printIdentifier(dependency.identifier) + printType(dependency.identifier.type); - return `${identifier}${dependency.path.map(token => `.${token.property}`).join('')}`; + return `${identifier}${dependency.path.map(token => `${token.optional ? '?.' : '.'}${token.property}`).join('')}`; } export function printReactiveInstructions( diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts index 8fd324ae2c9aa..4a054ab84c0bf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -6,6 +6,7 @@ */ import {CompilerError} from '../CompilerError'; +import {Environment} from '../HIR'; import { areEqualPaths, BlockId, @@ -22,6 +23,7 @@ import { PrunedReactiveScopeBlock, ReactiveFunction, ReactiveInstruction, + ReactiveOptionalCallValue, ReactiveScope, ReactiveScopeBlock, ReactiveScopeDependency, @@ -65,11 +67,7 @@ export function propagateScopeDependencies(fn: ReactiveFunction): void { }); } } - visitReactiveFunction( - fn, - new PropagationVisitor(fn.env.config.enableTreatFunctionDepsAsConditional), - context, - ); + visitReactiveFunction(fn, new PropagationVisitor(fn.env), context); } type TemporariesUsedOutsideDefiningScope = { @@ -465,6 +463,7 @@ class Context { #getProperty( object: Place, property: string, + optional: boolean, ): ReactiveScopePropertyDependency { const resolvedObject = this.resolveTemporary(object); const resolvedDependency = this.#properties.get(resolvedObject.identifier); @@ -485,13 +484,18 @@ class Context { }; } - objectDependency.path.push({property, optional: false}); + objectDependency.path.push({property, optional}); return objectDependency; } - declareProperty(lvalue: Place, object: Place, property: string): void { - const nextDependency = this.#getProperty(object, property); + declareProperty( + lvalue: Place, + object: Place, + property: string, + optional: boolean, + ): void { + const nextDependency = this.#getProperty(object, property, optional); this.#properties.set(lvalue.identifier, nextDependency); } @@ -571,8 +575,8 @@ class Context { this.visitDependency(dependency); } - visitProperty(object: Place, property: string): void { - const nextDependency = this.#getProperty(object, property); + visitProperty(object: Place, property: string, optional: boolean): void { + const nextDependency = this.#getProperty(object, property, optional); this.visitDependency(nextDependency); } @@ -671,12 +675,11 @@ class Context { } class PropagationVisitor extends ReactiveFunctionVisitor { - enableTreatFunctionDepsAsConditional = false; + env: Environment; - constructor(enableTreatFunctionDepsAsConditional: boolean) { + constructor(env: Environment) { super(); - this.enableTreatFunctionDepsAsConditional = - enableTreatFunctionDepsAsConditional; + this.env = env; } override visitScope(scope: ReactiveScopeBlock, context: Context): void { @@ -744,51 +747,212 @@ class PropagationVisitor extends ReactiveFunctionVisitor { }); } + extractOptionalProperty( + context: Context, + optionalValue: ReactiveOptionalCallValue, + lvalue: Place, + ): { + lvalue: Place; + object: Place; + property: string; + optional: boolean; + } | null { + const sequence = optionalValue.value; + CompilerError.invariant(sequence.kind === 'SequenceExpression', { + reason: 'Expected OptionalExpression value to be a SequenceExpression', + description: `Found a \`${sequence.kind}\``, + loc: sequence.loc, + }); + /** + * Base case: inner ` "." or "?."" ` + *``` + * = OptionalExpression optional=true (`optionalValue` is here) + * Sequence (`sequence` is here) + * t0 = LoadLocal + * Sequence + * t1 = PropertyLoad t0 . + * LoadLocal t1 + * ``` + */ + if ( + sequence.instructions.length === 1 && + sequence.instructions[0].value.kind === 'LoadLocal' && + sequence.instructions[0].lvalue !== null && + sequence.instructions[0].value.place.identifier.name !== null && + !context.isUsedOutsideDeclaringScope(sequence.instructions[0].lvalue) && + sequence.value.kind === 'SequenceExpression' && + sequence.value.instructions.length === 1 && + sequence.value.instructions[0].value.kind === 'PropertyLoad' && + sequence.value.instructions[0].value.object.identifier.id === + sequence.instructions[0].lvalue.identifier.id && + sequence.value.instructions[0].lvalue !== null && + sequence.value.value.kind === 'LoadLocal' && + sequence.value.value.place.identifier.id === + sequence.value.instructions[0].lvalue.identifier.id + ) { + context.declareTemporary( + sequence.instructions[0].lvalue, + sequence.instructions[0].value.place, + ); + const propertyLoad = sequence.value.instructions[0].value; + return { + lvalue, + object: propertyLoad.object, + property: propertyLoad.property, + optional: optionalValue.optional, + }; + } + /** + * Composed case: ` "." or "?." ` + * + * This case is convoluted, note how `t0` appears as an lvalue *twice* + * and then is an operand of an intermediate LoadLocal and then the + * object of the final PropertyLoad: + * + * ``` + * = OptionalExpression optional=false (`optionalValue` is here) + * Sequence (`sequence` is here) + * t0 = Sequence + * t0 = + * + * LoadLocal t0 + * Sequence + * t1 = PropertyLoad t0. + * LoadLocal t1 + * ``` + */ + if ( + sequence.instructions.length === 1 && + sequence.instructions[0].value.kind === 'SequenceExpression' && + sequence.instructions[0].value.instructions.length === 1 && + sequence.instructions[0].value.instructions[0].lvalue !== null && + sequence.instructions[0].value.instructions[0].value.kind === + 'OptionalExpression' && + sequence.instructions[0].value.value.kind === 'LoadLocal' && + sequence.instructions[0].value.value.place.identifier.id === + sequence.instructions[0].value.instructions[0].lvalue.identifier.id && + sequence.value.kind === 'SequenceExpression' && + sequence.value.instructions.length === 1 && + sequence.value.instructions[0].lvalue !== null && + sequence.value.instructions[0].value.kind === 'PropertyLoad' && + sequence.value.instructions[0].value.object.identifier.id === + sequence.instructions[0].value.value.place.identifier.id && + sequence.value.value.kind === 'LoadLocal' && + sequence.value.value.place.identifier.id === + sequence.value.instructions[0].lvalue.identifier.id + ) { + const {lvalue: innerLvalue, value: innerOptional} = + sequence.instructions[0].value.instructions[0]; + const innerProperty = this.extractOptionalProperty( + context, + innerOptional, + innerLvalue, + ); + if (innerProperty === null) { + return null; + } + context.declareProperty( + innerProperty.lvalue, + innerProperty.object, + innerProperty.property, + innerProperty.optional, + ); + const propertyLoad = sequence.value.instructions[0].value; + return { + lvalue, + object: propertyLoad.object, + property: propertyLoad.property, + optional: optionalValue.optional, + }; + } + return null; + } + + visitOptionalExpression( + context: Context, + id: InstructionId, + value: ReactiveOptionalCallValue, + lvalue: Place | null, + ): void { + /** + * If this is the first optional=true optional in a recursive OptionalExpression + * subtree, we check to see if the subtree is of the form: + * ``` + * NestedOptional = + * ` . / ?. ` + * ` . / ?. ` + * ``` + * + * Ie strictly a chain like `foo?.bar?.baz` or `a?.b.c`. If the subtree contains + * any other types of expressions - for example `foo?.[makeKey(a)]` - then this + * will return null and we'll go to the default handling below. + * + * If the tree does match the NestedOptional shape, then we'll have recorded + * a sequence of declareProperty calls, and the final visitProperty call here + * will record that optional chain as a dependency (since we know it's about + * to be referenced via its lvalue which is non-null). + */ + if ( + lvalue !== null && + value.optional && + this.env.config.enableOptionalDependencies + ) { + const inner = this.extractOptionalProperty(context, value, lvalue); + if (inner !== null) { + context.visitProperty(inner.object, inner.property, inner.optional); + return; + } + } + + // Otherwise we treat everything after the optional as conditional + const inner = value.value; + /* + * OptionalExpression value is a SequenceExpression where the instructions + * represent the code prior to the `?` and the final value represents the + * conditional code that follows. + */ + CompilerError.invariant(inner.kind === 'SequenceExpression', { + reason: 'Expected OptionalExpression value to be a SequenceExpression', + description: `Found a \`${value.kind}\``, + loc: value.loc, + suggestions: null, + }); + // Instructions are the unconditionally executed portion before the `?` + for (const instr of inner.instructions) { + this.visitInstruction(instr, context); + } + // The final value is the conditional portion following the `?` + context.enterConditional(() => { + this.visitReactiveValue(context, id, inner.value, null); + }); + } + visitReactiveValue( context: Context, id: InstructionId, value: ReactiveValue, + lvalue: Place | null, ): void { switch (value.kind) { case 'OptionalExpression': { - const inner = value.value; - /* - * OptionalExpression value is a SequenceExpression where the instructions - * represent the code prior to the `?` and the final value represents the - * conditional code that follows. - */ - CompilerError.invariant(inner.kind === 'SequenceExpression', { - reason: - 'Expected OptionalExpression value to be a SequenceExpression', - description: `Found a \`${value.kind}\``, - loc: value.loc, - suggestions: null, - }); - // Instructions are the unconditionally executed portion before the `?` - for (const instr of inner.instructions) { - this.visitInstruction(instr, context); - } - // The final value is the conditional portion following the `?` - context.enterConditional(() => { - this.visitReactiveValue(context, id, inner.value); - }); + this.visitOptionalExpression(context, id, value, lvalue); break; } case 'LogicalExpression': { - this.visitReactiveValue(context, id, value.left); + this.visitReactiveValue(context, id, value.left, null); context.enterConditional(() => { - this.visitReactiveValue(context, id, value.right); + this.visitReactiveValue(context, id, value.right, null); }); break; } case 'ConditionalExpression': { - this.visitReactiveValue(context, id, value.test); + this.visitReactiveValue(context, id, value.test, null); const consequentDeps = context.enterConditional(() => { - this.visitReactiveValue(context, id, value.consequent); + this.visitReactiveValue(context, id, value.consequent, null); }); const alternateDeps = context.enterConditional(() => { - this.visitReactiveValue(context, id, value.alternate); + this.visitReactiveValue(context, id, value.alternate, null); }); context.promoteDepsFromExhaustiveConditionals([ consequentDeps, @@ -804,7 +968,7 @@ class PropagationVisitor extends ReactiveFunctionVisitor { break; } case 'FunctionExpression': { - if (this.enableTreatFunctionDepsAsConditional) { + if (this.env.config.enableTreatFunctionDepsAsConditional) { context.enterConditional(() => { for (const operand of eachInstructionValueOperand(value)) { context.visitOperand(operand); @@ -851,9 +1015,9 @@ class PropagationVisitor extends ReactiveFunctionVisitor { } } else if (value.kind === 'PropertyLoad') { if (lvalue !== null && !context.isUsedOutsideDeclaringScope(lvalue)) { - context.declareProperty(lvalue, value.object, value.property); + context.declareProperty(lvalue, value.object, value.property, false); } else { - context.visitProperty(value.object, value.property); + context.visitProperty(value.object, value.property, false); } } else if (value.kind === 'StoreLocal') { context.visitOperand(value.value); @@ -896,7 +1060,7 @@ class PropagationVisitor extends ReactiveFunctionVisitor { }); } } else { - this.visitReactiveValue(context, id, value); + this.visitReactiveValue(context, id, value, lvalue); } } @@ -947,25 +1111,30 @@ class PropagationVisitor extends ReactiveFunctionVisitor { break; } case 'for': { - this.visitReactiveValue(context, terminal.id, terminal.init); - this.visitReactiveValue(context, terminal.id, terminal.test); + this.visitReactiveValue(context, terminal.id, terminal.init, null); + this.visitReactiveValue(context, terminal.id, terminal.test, null); context.enterConditional(() => { this.visitBlock(terminal.loop, context); if (terminal.update !== null) { - this.visitReactiveValue(context, terminal.id, terminal.update); + this.visitReactiveValue( + context, + terminal.id, + terminal.update, + null, + ); } }); break; } case 'for-of': { - this.visitReactiveValue(context, terminal.id, terminal.init); + this.visitReactiveValue(context, terminal.id, terminal.init, null); context.enterConditional(() => { this.visitBlock(terminal.loop, context); }); break; } case 'for-in': { - this.visitReactiveValue(context, terminal.id, terminal.init); + this.visitReactiveValue(context, terminal.id, terminal.init, null); context.enterConditional(() => { this.visitBlock(terminal.loop, context); }); @@ -974,12 +1143,12 @@ class PropagationVisitor extends ReactiveFunctionVisitor { case 'do-while': { this.visitBlock(terminal.loop, context); context.enterConditional(() => { - this.visitReactiveValue(context, terminal.id, terminal.test); + this.visitReactiveValue(context, terminal.id, terminal.test, null); }); break; } case 'while': { - this.visitReactiveValue(context, terminal.id, terminal.test); + this.visitReactiveValue(context, terminal.id, terminal.test, null); context.enterConditional(() => { this.visitBlock(terminal.loop, context); }); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md deleted file mode 100644 index 7e4145a27c16b..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.expect.md +++ /dev/null @@ -1,32 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees -function Component(props) { - const data = useMemo(() => { - return props.items?.edges?.nodes ?? []; - }, [props.items?.edges?.nodes]); - return ; -} - -``` - - -## Error - -``` - 1 | // @validatePreserveExistingMemoizationGuarantees - 2 | function Component(props) { -> 3 | const data = useMemo(() => { - | ^^^^^^^ -> 4 | return props.items?.edges?.nodes ?? []; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 5 | }, [props.items?.edges?.nodes]); - | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (3:5) - 6 | return ; - 7 | } - 8 | -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js deleted file mode 100644 index fd8cf0214c87b..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-member-expression-as-memo-dep.js +++ /dev/null @@ -1,7 +0,0 @@ -// @validatePreserveExistingMemoizationGuarantees -function Component(props) { - const data = useMemo(() => { - return props.items?.edges?.nodes ?? []; - }, [props.items?.edges?.nodes]); - return ; -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md new file mode 100644 index 0000000000000..c34b79a848ba8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md @@ -0,0 +1,48 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +function Component(props) { + const data = useMemo(() => { + return props?.items.edges?.nodes.map(); + }, [props?.items.edges?.nodes]); + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +function Component(props) { + const $ = _c(4); + + props?.items.edges?.nodes; + let t0; + let t1; + if ($[0] !== props?.items.edges?.nodes) { + t1 = props?.items.edges?.nodes.map(); + $[0] = props?.items.edges?.nodes; + $[1] = t1; + } else { + t1 = $[1]; + } + t0 = t1; + const data = t0; + let t2; + if ($[2] !== data) { + t2 = ; + $[2] = data; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js new file mode 100644 index 0000000000000..d82d36b547970 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js @@ -0,0 +1,7 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +function Component(props) { + const data = useMemo(() => { + return props?.items.edges?.nodes.map(); + }, [props?.items.edges?.nodes]); + return ; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md new file mode 100644 index 0000000000000..d0c4afe459da2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md @@ -0,0 +1,65 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + x.push(props.items); + return x; + }, [props?.items]); + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c(7); + + props?.items; + let t0; + let x; + if ($[0] !== props.items) { + x = []; + x.push(props?.items); + x.push(props.items); + $[0] = props.items; + $[1] = x; + } else { + x = $[1]; + } + t0 = x; + const data = t0; + const t1 = props?.items; + let t2; + if ($[2] !== t1) { + t2 = [t1]; + $[2] = t1; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== t2 || $[5] !== data) { + t3 = ; + $[4] = t2; + $[5] = data; + $[6] = t3; + } else { + t3 = $[6]; + } + return t3; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js new file mode 100644 index 0000000000000..c630dd6bb4b9d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js @@ -0,0 +1,11 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + x.push(props.items); + return x; + }, [props?.items]); + return ; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md new file mode 100644 index 0000000000000..a4cf6d767d1c3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md @@ -0,0 +1,63 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + return x; + }, [props?.items]); + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c(7); + + props?.items; + let t0; + let x; + if ($[0] !== props?.items) { + x = []; + x.push(props?.items); + $[0] = props?.items; + $[1] = x; + } else { + x = $[1]; + } + t0 = x; + const data = t0; + const t1 = props?.items; + let t2; + if ($[2] !== t1) { + t2 = [t1]; + $[2] = t1; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== t2 || $[5] !== data) { + t3 = ; + $[4] = t2; + $[5] = data; + $[6] = t3; + } else { + t3 = $[6]; + } + return t3; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js new file mode 100644 index 0000000000000..5750d7af3a0e0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js @@ -0,0 +1,10 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + return x; + }, [props?.items]); + return ; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md new file mode 100644 index 0000000000000..77ded20d939bd --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md @@ -0,0 +1,74 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + if (props.cond) { + x.push(props?.items); + } + return x; + }, [props?.items, props.cond]); + return ( + + ); +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c(9); + + props?.items; + let t0; + let x; + if ($[0] !== props?.items || $[1] !== props.cond) { + x = []; + x.push(props?.items); + if (props.cond) { + x.push(props?.items); + } + $[0] = props?.items; + $[1] = props.cond; + $[2] = x; + } else { + x = $[2]; + } + t0 = x; + const data = t0; + + const t1 = props?.items; + let t2; + if ($[3] !== t1 || $[4] !== props.cond) { + t2 = [t1, props.cond]; + $[3] = t1; + $[4] = props.cond; + $[5] = t2; + } else { + t2 = $[5]; + } + let t3; + if ($[6] !== t2 || $[7] !== data) { + t3 = ; + $[6] = t2; + $[7] = data; + $[8] = t3; + } else { + t3 = $[8]; + } + return t3; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.js new file mode 100644 index 0000000000000..760f345e90210 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.js @@ -0,0 +1,15 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + if (props.cond) { + x.push(props?.items); + } + return x; + }, [props?.items, props.cond]); + return ( + + ); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md new file mode 100644 index 0000000000000..10c23085d8e6b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md @@ -0,0 +1,74 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + if (props.cond) { + x.push(props.items); + } + return x; + }, [props?.items, props.cond]); + return ( + + ); +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c(9); + + props?.items; + let t0; + let x; + if ($[0] !== props?.items || $[1] !== props.cond) { + x = []; + x.push(props?.items); + if (props.cond) { + x.push(props.items); + } + $[0] = props?.items; + $[1] = props.cond; + $[2] = x; + } else { + x = $[2]; + } + t0 = x; + const data = t0; + + const t1 = props?.items; + let t2; + if ($[3] !== t1 || $[4] !== props.cond) { + t2 = [t1, props.cond]; + $[3] = t1; + $[4] = props.cond; + $[5] = t2; + } else { + t2 = $[5]; + } + let t3; + if ($[6] !== t2 || $[7] !== data) { + t3 = ; + $[6] = t2; + $[7] = data; + $[8] = t3; + } else { + t3 = $[8]; + } + return t3; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.js new file mode 100644 index 0000000000000..3f773f4fe4e4b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.js @@ -0,0 +1,15 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + if (props.cond) { + x.push(props.items); + } + return x; + }, [props?.items, props.cond]); + return ( + + ); +} From 99a4b26e18a71a2ed5af5ec11f4b9bace3882f7e Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 10:52:37 -0700 Subject: [PATCH 071/426] [compiler] Handle optional where innermost property access is non-optional Handles an additional case as part of testing combinations of the same path being accessed in different places with different segments as optional/unconditional. ghstack-source-id: ace777fcbb98fa8f41b977d0aec8418f3f58fb7b Pull Request resolved: https://github.com/facebook/react/pull/30836 --- .../PropagateScopeDependencies.ts | 82 ++++++++++++++++++- ...nverted-optionals-parallel-paths.expect.md | 46 +++++++++++ ...ssion-inverted-optionals-parallel-paths.js | 11 +++ 3 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts index 4a054ab84c0bf..dc1142b271e77 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -764,7 +764,7 @@ class PropagationVisitor extends ReactiveFunctionVisitor { loc: sequence.loc, }); /** - * Base case: inner ` "." or "?."" ` + * Base case: inner ` "?." ` *``` * = OptionalExpression optional=true (`optionalValue` is here) * Sequence (`sequence` is here) @@ -776,8 +776,8 @@ class PropagationVisitor extends ReactiveFunctionVisitor { */ if ( sequence.instructions.length === 1 && - sequence.instructions[0].value.kind === 'LoadLocal' && sequence.instructions[0].lvalue !== null && + sequence.instructions[0].value.kind === 'LoadLocal' && sequence.instructions[0].value.place.identifier.name !== null && !context.isUsedOutsideDeclaringScope(sequence.instructions[0].lvalue) && sequence.value.kind === 'SequenceExpression' && @@ -803,7 +803,83 @@ class PropagationVisitor extends ReactiveFunctionVisitor { }; } /** - * Composed case: ` "." or "?." ` + * Base case 2: inner ` "." "?." + * ``` + * = OptionalExpression optional=true (`optionalValue` is here) + * Sequence (`sequence` is here) + * t0 = Sequence + * t1 = LoadLocal + * ... // see note + * PropertyLoad t1 . + * [46] Sequence + * t2 = PropertyLoad t0 . + * [46] LoadLocal t2 + * ``` + * + * Note that it's possible to have additional inner chained non-optional + * property loads at "...", from an expression like `a?.b.c.d.e`. We could + * expand to support this case by relaxing the check on the inner sequence + * length, ensuring all instructions after the first LoadLocal are PropertyLoad + * and then iterating to ensure that the lvalue of the previous is always + * the object of the next PropertyLoad, w the final lvalue as the object + * of the sequence.value's object. + * + * But this case is likely rare in practice, usually once you're optional + * chaining all property accesses are optional (not `a?.b.c` but `a?.b?.c`). + * Also, HIR-based PropagateScopeDeps will handle this case so it doesn't + * seem worth it to optimize for that edge-case here. + */ + if ( + sequence.instructions.length === 1 && + sequence.instructions[0].lvalue !== null && + sequence.instructions[0].value.kind === 'SequenceExpression' && + sequence.instructions[0].value.instructions.length === 1 && + sequence.instructions[0].value.instructions[0].lvalue !== null && + sequence.instructions[0].value.instructions[0].value.kind === + 'LoadLocal' && + sequence.instructions[0].value.instructions[0].value.place.identifier + .name !== null && + !context.isUsedOutsideDeclaringScope( + sequence.instructions[0].value.instructions[0].lvalue, + ) && + sequence.instructions[0].value.value.kind === 'PropertyLoad' && + sequence.instructions[0].value.value.object.identifier.id === + sequence.instructions[0].value.instructions[0].lvalue.identifier.id && + sequence.value.kind === 'SequenceExpression' && + sequence.value.instructions.length === 1 && + sequence.value.instructions[0].lvalue !== null && + sequence.value.instructions[0].value.kind === 'PropertyLoad' && + sequence.value.instructions[0].value.object.identifier.id === + sequence.instructions[0].lvalue.identifier.id && + sequence.value.value.kind === 'LoadLocal' && + sequence.value.value.place.identifier.id === + sequence.value.instructions[0].lvalue.identifier.id + ) { + // LoadLocal + context.declareTemporary( + sequence.instructions[0].value.instructions[0].lvalue, + sequence.instructions[0].value.instructions[0].value.place, + ); + // PropertyLoad . (the inner non-optional property) + context.declareProperty( + sequence.instructions[0].lvalue, + sequence.instructions[0].value.value.object, + sequence.instructions[0].value.value.property, + false, + ); + const propertyLoad = sequence.value.instructions[0].value; + return { + lvalue, + object: propertyLoad.object, + property: propertyLoad.property, + optional: optionalValue.optional, + }; + } + + /** + * Composed case: + * - ` "." or "?." ` + * - ` "." or "?>" ` * * This case is convoluted, note how `t0` appears as an lvalue *twice* * and then is an operand of an intermediate LoadLocal and then the diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.expect.md new file mode 100644 index 0000000000000..98fcfbe7f0f6f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.expect.md @@ -0,0 +1,46 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.a.b?.c.d?.e); + x.push(props.a?.b.c?.d.e); + return x; + }, [props.a.b.c.d.e]); + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c(2); + let t0; + + const x$0 = []; + x$0.push(props?.a.b?.c.d?.e); + x$0.push(props.a?.b.c?.d.e); + t0 = x$0; + let t1; + if ($[0] !== props.a.b.c.d.e) { + t1 = ; + $[0] = props.a.b.c.d.e; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.js new file mode 100644 index 0000000000000..563b0bbf0f418 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-inverted-optionals-parallel-paths.js @@ -0,0 +1,11 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.a.b?.c.d?.e); + x.push(props.a?.b.c?.d.e); + return x; + }, [props.a.b.c.d.e]); + return ; +} From 3a45ba241c028cd0af7bf17bb4c6487d0095a10f Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 12:12:29 -0700 Subject: [PATCH 072/426] [compiler] Enable optional dependencies by default Per title. This gives us much more granular memoization when the source used optional member expressions. Note that we only infer optional deps when the source used optionals: we don't (yet) infer optional dependencies from conditionals. ghstack-source-id: 104d0b712d09498239e926e306c4623d546463b1 Pull Request resolved: https://github.com/facebook/react/pull/30838 --- .../src/HIR/Environment.ts | 2 +- ...call-with-optional-property-load.expect.md | 4 ++-- ...less-specific-conditional-access.expect.md | 2 -- .../conditional-member-expr.expect.md | 4 ++-- .../memberexpr-join-optional-chain.expect.md | 4 ++-- .../memberexpr-join-optional-chain2.expect.md | 21 +++++++++++++------ ...epro-scope-missing-mutable-range.expect.md | 4 ++-- 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index a13ebb6aac878..2b007f9659b99 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -230,7 +230,7 @@ const EnvironmentConfigSchema = z.object({ * just `props`. With this flag enabled, we'll infer that full path as * the dependency. */ - enableOptionalDependencies: z.boolean().default(false), + enableOptionalDependencies: z.boolean().default(true), /* * Enable validation of hooks to partially check that the component honors the rules of hooks. diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-with-optional-property-load.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-with-optional-property-load.expect.md index 795ab61cca997..d95461adf90e6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-with-optional-property-load.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-call-with-optional-property-load.expect.md @@ -15,9 +15,9 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(2); let t0; - if ($[0] !== props) { + if ($[0] !== props?.items) { t0 = props?.items?.map?.(render)?.filter(Boolean) ?? []; - $[0] = props; + $[0] = props?.items; $[1] = t0; } else { t0 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md index 0cda150692955..25d7bf5f7ccce 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useMemo-infer-less-specific-conditional-access.expect.md @@ -44,8 +44,6 @@ function Component({propA, propB}) { | ^^^^^^^^^^^^^^^^^ > 14 | }, [propA?.a, propB.x.y]); | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14) - -CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14) 15 | } 16 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/conditional-member-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/conditional-member-expr.expect.md index 59b48898fda16..2dd61732f689f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/conditional-member-expr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/conditional-member-expr.expect.md @@ -29,10 +29,10 @@ import { c as _c } from "react/compiler-runtime"; // To preserve the nullthrows function Component(props) { const $ = _c(2); let x; - if ($[0] !== props.a) { + if ($[0] !== props.a?.b) { x = []; x.push(props.a?.b); - $[0] = props.a; + $[0] = props.a?.b; $[1] = x; } else { x = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md index 7362cd8317091..a66540655ab79 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md @@ -44,11 +44,11 @@ import { c as _c } from "react/compiler-runtime"; // To preserve the nullthrows function Component(props) { const $ = _c(2); let x; - if ($[0] !== props.a) { + if ($[0] !== props.a.b) { x = []; x.push(props.a?.b); x.push(props.a.b.c); - $[0] = props.a; + $[0] = props.a.b; $[1] = x; } else { x = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md index f25ea2a31e552..8d69c008c573b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md @@ -21,16 +21,25 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(5); let x; - if ($[0] !== props.items) { + if ($[0] !== props.items?.length || $[1] !== props.items?.edges) { x = []; x.push(props.items?.length); - x.push(props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []); - $[0] = props.items; - $[1] = x; + let t0; + if ($[3] !== props.items?.edges) { + t0 = props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []; + $[3] = props.items?.edges; + $[4] = t0; + } else { + t0 = $[4]; + } + x.push(t0); + $[0] = props.items?.length; + $[1] = props.items?.edges; + $[2] = x; } else { - x = $[1]; + x = $[2]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md index 2ce8ffbe4c92e..d8e59c486a55b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-scope-missing-mutable-range.expect.md @@ -23,14 +23,14 @@ function HomeDiscoStoreItemTileRating(props) { const $ = _c(4); const item = useFragment(); let count; - if ($[0] !== item) { + if ($[0] !== item?.aggregates) { count = 0; const aggregates = item?.aggregates || []; aggregates.forEach((aggregate) => { count = count + (aggregate.count || 0); count; }); - $[0] = item; + $[0] = item?.aggregates; $[1] = count; } else { count = $[1]; From fc0df475c4417670272b819bad92590b310bcdaa Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Wed, 28 Aug 2024 15:16:02 -0700 Subject: [PATCH 073/426] [compiler] Inferred deps must match exact optionality of manual deps To prevent any difference in behavior, we check that the optionality of the inferred deps exactly matches the optionality of the manual dependencies. This required a fix, I was incorrectly inferring optionality of manual deps (they're only optional if OptionalTerminal.optional is true) - for nested cases of mixed optional/non-optional. ghstack-source-id: afd49e89cc3194eb3c317ca7434d3fa948896bff Pull Request resolved: https://github.com/facebook/react/pull/30840 --- .../src/Inference/DropManualMemoization.ts | 2 +- .../ValidatePreservedManualMemoization.ts | 2 +- ...as-memo-dep-non-optional-in-body.expect.md | 38 ++++++++++++++ ...ssion-as-memo-dep-non-optional-in-body.js} | 0 ...as-memo-dep-non-optional-in-body.expect.md | 50 ------------------- ...ession-single-with-unconditional.expect.md | 33 ++++++------ ...er-expression-single-with-unconditional.js | 4 +- 7 files changed, 57 insertions(+), 72 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{optional-member-expression-as-memo-dep-non-optional-in-body.js => error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.js} (100%) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts index fdd9bcc968aef..4dcdc21e15ac5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/DropManualMemoization.ts @@ -488,7 +488,7 @@ export function dropManualMemoization(func: HIRFunction): void { function findOptionalPlaces(fn: HIRFunction): Set { const optionals = new Set(); for (const [, block] of fn.body.blocks) { - if (block.terminal.kind === 'optional') { + if (block.terminal.kind === 'optional' && block.terminal.optional) { const optionalTerminal = block.terminal; let testBlock = fn.body.blocks.get(block.terminal.test)!; loop: while (true) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts index 4f0c756585cf0..e7615320c7b95 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidatePreservedManualMemoization.ts @@ -170,7 +170,7 @@ function compareDeps( if (inferred.path[i].property !== source.path[i].property) { isSubpath = false; break; - } else if (inferred.path[i].optional && !source.path[i].optional) { + } else if (inferred.path[i].optional !== source.path[i].optional) { /** * The inferred path must be at least as precise as the manual path: * if the inferred path is optional, then the source path must have diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md new file mode 100644 index 0000000000000..ba5b30418069a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.expect.md @@ -0,0 +1,38 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +function Component(props) { + const data = useMemo(() => { + // actual code is non-optional + return props.items.edges.nodes ?? []; + // deps are optional + }, [props.items?.edges?.nodes]); + return ; +} + +``` + + +## Error + +``` + 1 | // @validatePreserveExistingMemoizationGuarantees + 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]); + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (3:7) + 8 | return ; + 9 | } + 10 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-optional-member-expression-as-memo-dep-non-optional-in-body.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md deleted file mode 100644 index 7cf1bcd90b339..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep-non-optional-in-body.expect.md +++ /dev/null @@ -1,50 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees -function Component(props) { - const data = useMemo(() => { - // actual code is non-optional - return props.items.edges.nodes ?? []; - // deps are optional - }, [props.items?.edges?.nodes]); - return ; -} - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees -function Component(props) { - const $ = _c(4); - - props.items?.edges?.nodes; - let t0; - let t1; - if ($[0] !== props.items.edges.nodes) { - t1 = props.items.edges.nodes ?? []; - $[0] = props.items.edges.nodes; - $[1] = t1; - } else { - t1 = $[1]; - } - t0 = t1; - const data = t0; - let t2; - if ($[2] !== data) { - t2 = ; - $[2] = data; - $[3] = t2; - } else { - t2 = $[3]; - } - return t2; -} - -``` - -### Eval output -(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md index d0c4afe459da2..46767056bdcdf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md @@ -10,8 +10,8 @@ function Component(props) { x.push(props?.items); x.push(props.items); return x; - }, [props?.items]); - return ; + }, [props.items]); + return ; } ``` @@ -23,8 +23,6 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe import { ValidateMemoization } from "shared-runtime"; function Component(props) { const $ = _c(7); - - props?.items; let t0; let x; if ($[0] !== props.items) { @@ -38,25 +36,24 @@ function Component(props) { } t0 = x; const data = t0; - const t1 = props?.items; - let t2; - if ($[2] !== t1) { - t2 = [t1]; - $[2] = t1; - $[3] = t2; + let t1; + if ($[2] !== props.items) { + t1 = [props.items]; + $[2] = props.items; + $[3] = t1; } else { - t2 = $[3]; + t1 = $[3]; } - let t3; - if ($[4] !== t2 || $[5] !== data) { - t3 = ; - $[4] = t2; + let t2; + if ($[4] !== t1 || $[5] !== data) { + t2 = ; + $[4] = t1; $[5] = data; - $[6] = t3; + $[6] = t2; } else { - t3 = $[6]; + t2 = $[6]; } - return t3; + return t2; } ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js index c630dd6bb4b9d..8e6275bf921eb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.js @@ -6,6 +6,6 @@ function Component(props) { x.push(props?.items); x.push(props.items); return x; - }, [props?.items]); - return ; + }, [props.items]); + return ; } From 537c74e16a394df16a4b368caa09ea5755f78dfb Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 29 Aug 2024 11:28:35 +0100 Subject: [PATCH 074/426] feat[react-devtools]: support Manifest v3 for Firefox extension (#30824) Firefox [finally supports `ExecutionWorld.MAIN`](https://bugzilla.mozilla.org/show_bug.cgi?id=1736575) in content scripts, which means we can migrate the browser extension to Manifest V3. This PR also removes a bunch of no longer required explicit branching for Firefox case, when we are using Manifest V3-only APIs. We are also removing XMLHttpRequest injection, which is no longer needed and restricted in Manifest V3. The new standardized approach (same as in Chromium) doesn't violate CSP rules, which means that extension can finally be used for apps running in production mode. --- .../firefox/manifest.json | 40 +++++---- .../dynamicallyInjectContentScripts.js | 90 +++++++------------ .../src/background/executeScript.js | 39 -------- .../background/setExtensionIconAndPopup.js | 6 +- .../src/background/tabsManager.js | 24 ++--- .../src/contentScripts/prepareInjection.js | 40 --------- .../react-devtools-shared/babel.config.js | 2 +- 7 files changed, 66 insertions(+), 175 deletions(-) diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json index ffa48634e0e0d..3c2d417d585af 100644 --- a/packages/react-devtools-extensions/firefox/manifest.json +++ b/packages/react-devtools-extensions/firefox/manifest.json @@ -1,12 +1,12 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Firefox Developer Tools.", "version": "5.3.1", - "applications": { + "browser_specific_settings": { "gecko": { "id": "@react-devtools", - "strict_min_version": "102.0" + "strict_min_version": "128.0" } }, "icons": { @@ -15,22 +15,32 @@ "48": "icons/48-production.png", "128": "icons/128-production.png" }, - "browser_action": { + "action": { "default_icon": { "16": "icons/16-disabled.png", "32": "icons/32-disabled.png", "48": "icons/48-disabled.png", "128": "icons/128-disabled.png" }, - "default_popup": "popups/disabled.html", - "browser_style": true + "default_popup": "popups/disabled.html" }, "devtools_page": "main.html", - "content_security_policy": "script-src 'self' 'unsafe-eval' blob:; object-src 'self'", + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'" + }, "web_accessible_resources": [ - "main.html", - "panel.html", - "build/*.js" + { + "resources": [ + "main.html", + "panel.html", + "build/*.js", + "build/*.js.map" + ], + "matches": [ + "" + ], + "extension_ids": [] + } ], "background": { "scripts": [ @@ -38,12 +48,10 @@ ] }, "permissions": [ - "file:///*", - "http://*/*", - "https://*/*", - "clipboardWrite", - "scripting", - "devtools" + "scripting" + ], + "host_permissions": [ + "" ], "content_scripts": [ { diff --git a/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js b/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js index e19030457a89c..b1888b4e7cc59 100644 --- a/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js +++ b/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js @@ -1,58 +1,39 @@ /* global chrome */ -// Firefox doesn't support ExecutionWorld.MAIN yet -// equivalent logic for Firefox is in prepareInjection.js -const contentScriptsToInject = __IS_FIREFOX__ - ? [ - { - id: '@react-devtools/proxy', - js: ['build/proxy.js'], - matches: [''], - persistAcrossSessions: true, - runAt: 'document_end', - }, - { - id: '@react-devtools/file-fetcher', - js: ['build/fileFetcher.js'], - matches: [''], - persistAcrossSessions: true, - runAt: 'document_end', - }, - ] - : [ - { - id: '@react-devtools/proxy', - js: ['build/proxy.js'], - matches: [''], - persistAcrossSessions: true, - runAt: 'document_end', - world: chrome.scripting.ExecutionWorld.ISOLATED, - }, - { - id: '@react-devtools/file-fetcher', - js: ['build/fileFetcher.js'], - matches: [''], - persistAcrossSessions: true, - runAt: 'document_end', - world: chrome.scripting.ExecutionWorld.ISOLATED, - }, - { - id: '@react-devtools/hook', - js: ['build/installHook.js'], - matches: [''], - persistAcrossSessions: true, - runAt: 'document_start', - world: chrome.scripting.ExecutionWorld.MAIN, - }, - { - id: '@react-devtools/renderer', - js: ['build/renderer.js'], - matches: [''], - persistAcrossSessions: true, - runAt: 'document_start', - world: chrome.scripting.ExecutionWorld.MAIN, - }, - ]; +const contentScriptsToInject = [ + { + id: '@react-devtools/proxy', + js: ['build/proxy.js'], + matches: [''], + persistAcrossSessions: true, + runAt: 'document_end', + world: chrome.scripting.ExecutionWorld.ISOLATED, + }, + { + id: '@react-devtools/file-fetcher', + js: ['build/fileFetcher.js'], + matches: [''], + persistAcrossSessions: true, + runAt: 'document_end', + world: chrome.scripting.ExecutionWorld.ISOLATED, + }, + { + id: '@react-devtools/hook', + js: ['build/installHook.js'], + matches: [''], + persistAcrossSessions: true, + runAt: 'document_start', + world: chrome.scripting.ExecutionWorld.MAIN, + }, + { + id: '@react-devtools/renderer', + js: ['build/renderer.js'], + matches: [''], + persistAcrossSessions: true, + runAt: 'document_start', + world: chrome.scripting.ExecutionWorld.MAIN, + }, +]; async function dynamicallyInjectContentScripts() { try { @@ -61,9 +42,6 @@ async function dynamicallyInjectContentScripts() { // This fixes registering proxy content script in incognito mode await chrome.scripting.unregisterContentScripts(); - // equivalent logic for Firefox is in prepareInjection.js - // Manifest V3 method of injecting content script - // TODO(hoxyq): migrate Firefox to V3 manifests // Note: the "world" option in registerContentScripts is only available in Chrome v102+ // It's critical since it allows us to directly run scripts on the "main" world on the page // "document_start" allows it to run before the page's scripts diff --git a/packages/react-devtools-extensions/src/background/executeScript.js b/packages/react-devtools-extensions/src/background/executeScript.js index efe73229ecff5..8b80095d33c2e 100644 --- a/packages/react-devtools-extensions/src/background/executeScript.js +++ b/packages/react-devtools-extensions/src/background/executeScript.js @@ -1,40 +1,5 @@ /* global chrome */ -// Firefox doesn't support ExecutionWorld.MAIN yet -// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575 -function executeScriptForFirefoxInMainWorld({target, files}) { - return chrome.scripting.executeScript({ - target, - func: fileNames => { - function injectScriptSync(src) { - let code = ''; - const request = new XMLHttpRequest(); - request.addEventListener('load', function () { - code = this.responseText; - }); - request.open('GET', src, false); - request.send(); - - const script = document.createElement('script'); - script.textContent = code; - - // This script runs before the element is created, - // so we add the script to instead. - if (document.documentElement) { - document.documentElement.appendChild(script); - } - - if (script.parentNode) { - script.parentNode.removeChild(script); - } - } - - fileNames.forEach(file => injectScriptSync(chrome.runtime.getURL(file))); - }, - args: [files], - }); -} - export function executeScriptInIsolatedWorld({target, files}) { return chrome.scripting.executeScript({ target, @@ -44,10 +9,6 @@ export function executeScriptInIsolatedWorld({target, files}) { } export function executeScriptInMainWorld({target, files}) { - if (__IS_FIREFOX__) { - return executeScriptForFirefoxInMainWorld({target, files}); - } - return chrome.scripting.executeScript({ target, files, diff --git a/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js b/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js index 5c6e011114014..51f233e284f0e 100644 --- a/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js +++ b/packages/react-devtools-extensions/src/background/setExtensionIconAndPopup.js @@ -3,9 +3,7 @@ 'use strict'; function setExtensionIconAndPopup(reactBuildType, tabId) { - const action = __IS_FIREFOX__ ? chrome.browserAction : chrome.action; - - action.setIcon({ + chrome.action.setIcon({ tabId, path: { '16': chrome.runtime.getURL(`icons/16-${reactBuildType}.png`), @@ -15,7 +13,7 @@ function setExtensionIconAndPopup(reactBuildType, tabId) { }, }); - action.setPopup({ + chrome.action.setPopup({ tabId, popup: chrome.runtime.getURL(`popups/${reactBuildType}.html`), }); diff --git a/packages/react-devtools-extensions/src/background/tabsManager.js b/packages/react-devtools-extensions/src/background/tabsManager.js index 23b566502a269..192a6ce42ce28 100644 --- a/packages/react-devtools-extensions/src/background/tabsManager.js +++ b/packages/react-devtools-extensions/src/background/tabsManager.js @@ -18,26 +18,12 @@ function checkAndHandleRestrictedPageIfSo(tab) { // we can't update for any other types (prod,dev,outdated etc) // as the content script needs to be injected at document_start itself for those kinds of detection // TODO: Show a different popup page(to reload current page probably) for old tabs, opened before the extension is installed -if (__IS_CHROME__ || __IS_EDGE__) { - chrome.tabs.query({}, tabs => tabs.forEach(checkAndHandleRestrictedPageIfSo)); - chrome.tabs.onCreated.addListener((tabId, changeInfo, tab) => - checkAndHandleRestrictedPageIfSo(tab), - ); -} +chrome.tabs.query({}, tabs => tabs.forEach(checkAndHandleRestrictedPageIfSo)); +chrome.tabs.onCreated.addListener((tabId, changeInfo, tab) => + checkAndHandleRestrictedPageIfSo(tab), +); // Listen to URL changes on the active tab and update the DevTools icon. chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - if (__IS_FIREFOX__) { - // We don't properly detect protected URLs in Firefox at the moment. - // However, we can reset the DevTools icon to its loading state when the URL changes. - // It will be updated to the correct icon by the onMessage callback below. - if (tab.active && changeInfo.status === 'loading') { - setExtensionIconAndPopup('disabled', tabId); - } - } else { - // Don't reset the icon to the loading state for Chrome or Edge. - // The onUpdated callback fires more frequently for these browsers, - // often after onMessage has been called. - checkAndHandleRestrictedPageIfSo(tab); - } + checkAndHandleRestrictedPageIfSo(tab); }); diff --git a/packages/react-devtools-extensions/src/contentScripts/prepareInjection.js b/packages/react-devtools-extensions/src/contentScripts/prepareInjection.js index d67ea7c405a1e..1b9962a9a826f 100644 --- a/packages/react-devtools-extensions/src/contentScripts/prepareInjection.js +++ b/packages/react-devtools-extensions/src/contentScripts/prepareInjection.js @@ -1,31 +1,5 @@ /* global chrome */ -import nullthrows from 'nullthrows'; - -// We run scripts on the page via the service worker (background/index.js) for -// Manifest V3 extensions (Chrome & Edge). -// We need to inject this code for Firefox only because it does not support ExecutionWorld.MAIN -// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/scripting/ExecutionWorld -// In this content script we have access to DOM, but don't have access to the webpage's window, -// so we inject this inline script tag into the webpage (allowed in Manifest V2). -function injectScriptSync(src) { - let code = ''; - const request = new XMLHttpRequest(); - request.addEventListener('load', function () { - code = this.responseText; - }); - request.open('GET', src, false); - request.send(); - - const script = document.createElement('script'); - script.textContent = code; - - // This script runs before the element is created, - // so we add the script to instead. - nullthrows(document.documentElement).appendChild(script); - nullthrows(script.parentNode).removeChild(script); -} - let lastSentDevToolsHookMessage; // We want to detect when a renderer attaches, and notify the "background page" @@ -60,17 +34,3 @@ window.addEventListener('pageshow', function ({target}) { chrome.runtime.sendMessage(lastSentDevToolsHookMessage); }); - -if (__IS_FIREFOX__) { - injectScriptSync(chrome.runtime.getURL('build/renderer.js')); - - // Inject a __REACT_DEVTOOLS_GLOBAL_HOOK__ global for React to interact with. - // Only do this for HTML documents though, to avoid e.g. breaking syntax highlighting for XML docs. - switch (document.contentType) { - case 'text/html': - case 'application/xhtml+xml': { - injectScriptSync(chrome.runtime.getURL('build/installHook.js')); - break; - } - } -} diff --git a/packages/react-devtools-shared/babel.config.js b/packages/react-devtools-shared/babel.config.js index ca877aa683afd..78af34817e0a9 100644 --- a/packages/react-devtools-shared/babel.config.js +++ b/packages/react-devtools-shared/babel.config.js @@ -3,7 +3,7 @@ const firefoxManifest = require('../react-devtools-extensions/firefox/manifest.j const minChromeVersion = parseInt(chromeManifest.minimum_chrome_version, 10); const minFirefoxVersion = parseInt( - firefoxManifest.applications.gecko.strict_min_version, + firefoxManifest.browser_specific_settings.gecko.strict_min_version, 10, ); validateVersion(minChromeVersion); From 795b3207ce5ea25c80749e367c61e5f56ac09856 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 29 Aug 2024 11:31:43 +0100 Subject: [PATCH 075/426] fix[react-devtools/extensions]: fixed tabs API calls and displaying restricted access popup (#30825) Stacked on https://github.com/facebook/react/pull/30824. See [this commit](https://github.com/facebook/react/pull/30825/commits/c9830d64749cf8fd592ea30a1cd65842cf83f6df). Turns out we should be listing `tabs` in our permissions, if we want to be able to receive tab url, once its updated. This also fixes `chrome.tabs.onCreated` event subscription, because [it should receive only tab object](https://developer.chrome.com/docs/extensions/reference/api/tabs#event-onCreated), and not 3 arguments, as expected in the previous implementation. --- .../chrome/manifest.json | 3 ++- .../edge/manifest.json | 3 ++- .../firefox/manifest.json | 3 ++- .../src/background/tabsManager.js | 20 ++++++++++--------- .../src/main/registerEventsLogger.js | 10 ++-------- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/react-devtools-extensions/chrome/manifest.json b/packages/react-devtools-extensions/chrome/manifest.json index 4dcd951a480ac..e7b9b19b6a9df 100644 --- a/packages/react-devtools-extensions/chrome/manifest.json +++ b/packages/react-devtools-extensions/chrome/manifest.json @@ -42,7 +42,8 @@ }, "permissions": [ "storage", - "scripting" + "scripting", + "tabs" ], "host_permissions": [ "" diff --git a/packages/react-devtools-extensions/edge/manifest.json b/packages/react-devtools-extensions/edge/manifest.json index fd19f1c5df532..496d4e92c3b63 100644 --- a/packages/react-devtools-extensions/edge/manifest.json +++ b/packages/react-devtools-extensions/edge/manifest.json @@ -42,7 +42,8 @@ }, "permissions": [ "storage", - "scripting" + "scripting", + "tabs" ], "host_permissions": [ "" diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json index 3c2d417d585af..930c1ab11083e 100644 --- a/packages/react-devtools-extensions/firefox/manifest.json +++ b/packages/react-devtools-extensions/firefox/manifest.json @@ -48,7 +48,8 @@ ] }, "permissions": [ - "scripting" + "scripting", + "tabs" ], "host_permissions": [ "" diff --git a/packages/react-devtools-extensions/src/background/tabsManager.js b/packages/react-devtools-extensions/src/background/tabsManager.js index 192a6ce42ce28..d46c14c6ea7c3 100644 --- a/packages/react-devtools-extensions/src/background/tabsManager.js +++ b/packages/react-devtools-extensions/src/background/tabsManager.js @@ -5,7 +5,12 @@ import setExtensionIconAndPopup from './setExtensionIconAndPopup'; function isRestrictedBrowserPage(url) { - return !url || new URL(url).protocol === 'chrome:'; + if (!url) { + return true; + } + + const urlProtocol = new URL(url).protocol; + return urlProtocol === 'chrome:' || urlProtocol === 'about:'; } function checkAndHandleRestrictedPageIfSo(tab) { @@ -14,16 +19,13 @@ function checkAndHandleRestrictedPageIfSo(tab) { } } -// update popup page of any existing open tabs, if they are restricted browser pages. -// we can't update for any other types (prod,dev,outdated etc) -// as the content script needs to be injected at document_start itself for those kinds of detection -// TODO: Show a different popup page(to reload current page probably) for old tabs, opened before the extension is installed +// Update popup page of any existing open tabs, if they are restricted browser pages chrome.tabs.query({}, tabs => tabs.forEach(checkAndHandleRestrictedPageIfSo)); -chrome.tabs.onCreated.addListener((tabId, changeInfo, tab) => - checkAndHandleRestrictedPageIfSo(tab), -); +chrome.tabs.onCreated.addListener(tab => checkAndHandleRestrictedPageIfSo(tab)); // Listen to URL changes on the active tab and update the DevTools icon. chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - checkAndHandleRestrictedPageIfSo(tab); + if (changeInfo.url && isRestrictedBrowserPage(changeInfo.url)) { + setExtensionIconAndPopup('restricted', tabId); + } }); diff --git a/packages/react-devtools-extensions/src/main/registerEventsLogger.js b/packages/react-devtools-extensions/src/main/registerEventsLogger.js index 5234866fd546c..ec57d173e42ca 100644 --- a/packages/react-devtools-extensions/src/main/registerEventsLogger.js +++ b/packages/react-devtools-extensions/src/main/registerEventsLogger.js @@ -4,14 +4,8 @@ import {registerDevToolsEventLogger} from 'react-devtools-shared/src/registerDev function registerEventsLogger() { registerDevToolsEventLogger('extension', async () => { - // TODO: after we upgrade to Firefox Manifest V3, chrome.tabs.query returns a Promise without the callback. - return new Promise(resolve => { - chrome.tabs.query({active: true}, tabs => { - resolve({ - page_url: tabs[0]?.url, - }); - }); - }); + const tabs = await chrome.tabs.query({active: true}); + return {page_url: tabs[0]?.url}; }); } From 233d63c497d3a5f669a1bae1ee1d3f389e12a42a Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 29 Aug 2024 11:32:18 +0100 Subject: [PATCH 076/426] chore[react-devtools/extensions]: remove unused storage permission (#30826) Stacked on https://github.com/facebook/react/pull/30825. See [this commit](https://github.com/facebook/react/pull/30826/commits/b2130701cf6b25d7a96c1e92b44f41affa56bb35). We are not using `storage` anywhere yet, but will be soon. This permission is not needed. --- packages/react-devtools-extensions/chrome/manifest.json | 1 - packages/react-devtools-extensions/edge/manifest.json | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/react-devtools-extensions/chrome/manifest.json b/packages/react-devtools-extensions/chrome/manifest.json index e7b9b19b6a9df..e61ebd1e57ed0 100644 --- a/packages/react-devtools-extensions/chrome/manifest.json +++ b/packages/react-devtools-extensions/chrome/manifest.json @@ -41,7 +41,6 @@ "service_worker": "build/background.js" }, "permissions": [ - "storage", "scripting", "tabs" ], diff --git a/packages/react-devtools-extensions/edge/manifest.json b/packages/react-devtools-extensions/edge/manifest.json index 496d4e92c3b63..48a56c7400ce4 100644 --- a/packages/react-devtools-extensions/edge/manifest.json +++ b/packages/react-devtools-extensions/edge/manifest.json @@ -41,7 +41,6 @@ "service_worker": "build/background.js" }, "permissions": [ - "storage", "scripting", "tabs" ], From a19a8ab44f53f189745015a6d2e6bf8955f98170 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 29 Aug 2024 11:34:31 +0100 Subject: [PATCH 077/426] chore[react-devtools/hook]: remove unused native values (#30827) Stacked on https://github.com/facebook/react/pull/30826. See [this commit](https://github.com/facebook/react/pull/30827/commits/ec0e48ed7a47dbbdafb5e2530ccba1f2e5b17bad). This is unused. --- .../src/contentScripts/installHook.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/react-devtools-extensions/src/contentScripts/installHook.js b/packages/react-devtools-extensions/src/contentScripts/installHook.js index 2d33cdd89036d..ff7e041627f0e 100644 --- a/packages/react-devtools-extensions/src/contentScripts/installHook.js +++ b/packages/react-devtools-extensions/src/contentScripts/installHook.js @@ -20,10 +20,4 @@ if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { ); }, ); - - // save native values - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeObjectCreate = Object.create; - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeMap = Map; - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeWeakMap = WeakMap; - window.__REACT_DEVTOOLS_GLOBAL_HOOK__.nativeSet = Set; } From 18bf7bf5002450ce7daa281e8be1c3216bd871ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 29 Aug 2024 12:44:48 -0400 Subject: [PATCH 078/426] [DevTools] Remove displayName from inspected data (#30841) This just clarifies that this is actually unused in the front end. We use the name from the original instance as the canonical name. --- .../src/backend/fiber/renderer.js | 13 +++---------- .../src/backend/legacy/renderer.js | 8 ++++---- packages/react-devtools-shared/src/backend/types.js | 2 -- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 729c8fce5a7a5..09b599a4d09c4 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -4212,7 +4212,6 @@ export function attach( key: key != null ? key : null, - displayName: getDisplayNameForFiber(fiber), type: elementType, // Inspectable properties. @@ -4252,13 +4251,6 @@ export function attach( typeof componentInfo.key === 'string' ? componentInfo.key : null; const props = null; // TODO: Track props on ReactComponentInfo; - const env = componentInfo.env; - let displayName = componentInfo.name || ''; - if (typeof env === 'string') { - // We model environment as an HoC name for now. - displayName = env + '(' + displayName + ')'; - } - const owners: null | Array = getOwnersListFromInstance(virtualInstance); @@ -4311,7 +4303,6 @@ export function attach( key: key, - displayName: displayName, type: ElementTypeVirtual, // Inspectable properties. @@ -4675,10 +4666,12 @@ export function attach( return; } + const displayName = getDisplayNameForElementID(id); + const supportsGroup = typeof console.groupCollapsed === 'function'; if (supportsGroup) { console.groupCollapsed( - `[Click to expand] %c<${result.displayName || 'Component'} />`, + `[Click to expand] %c<${displayName || 'Component'} />`, // --dom-tag-name-color is the CSS variable Chrome styles HTML elements with in the console. 'color: var(--dom-tag-name-color); font-weight: normal;', ); diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index f8aa548a0573a..523fbbeba3d8e 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -775,7 +775,7 @@ export function attach( return null; } - const {displayName, key} = getData(internalInstance); + const {key} = getData(internalInstance); const type = getElementType(internalInstance); let context = null; @@ -842,8 +842,6 @@ export function attach( // Only legacy context exists in legacy versions. hasLegacyContext: true, - displayName: displayName, - type: type, key: key != null ? key : null, @@ -876,10 +874,12 @@ export function attach( return; } + const displayName = getDisplayNameForElementID(id); + const supportsGroup = typeof console.groupCollapsed === 'function'; if (supportsGroup) { console.groupCollapsed( - `[Click to expand] %c<${result.displayName || 'Component'} />`, + `[Click to expand] %c<${displayName || 'Component'} />`, // --dom-tag-name-color is the CSS variable Chrome styles HTML elements with in the console. 'color: var(--dom-tag-name-color); font-weight: normal;', ); diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 87b0f2048b9db..41c278d02ebdf 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -239,8 +239,6 @@ export type OwnersList = { export type InspectedElement = { id: number, - displayName: string | null, - // Does the current renderer support editable hooks and function props? canEditHooks: boolean, canEditFunctionProps: boolean, From e33a7233a76e1164bd1a9c4b8115abb575b48c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 29 Aug 2024 12:45:03 -0400 Subject: [PATCH 079/426] [DevTools] Track virtual instances on the tracked path for selections (#30802) This appends a (filtered) virtual instance path at the end of the fiber path. If a virtual instance is selected inside the fiber. The main part of the path is still just the fiber path since that's the semantically stateful part. Then we just tack on a few virtual path frames at the end if we're currently selecting a specific Server Component within the nearest Fiber. I also took the opportunity to fix a bug which caused selections inside Suspense boundaries to not be tracked. --- .../src/backend/fiber/renderer.js | 160 +++++++++++++----- 1 file changed, 121 insertions(+), 39 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 09b599a4d09c4..0a19c79718c74 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -2266,16 +2266,11 @@ export function attach( debug('recordUnmount()', fiber, null); } - if (trackedPathMatchFiber !== null) { + if (trackedPathMatchInstance === fiberInstance) { // We're in the process of trying to restore previous selection. // If this fiber matched but is being unmounted, there's no use trying. // Reset the state so we don't keep holding onto it. - if ( - fiber === trackedPathMatchFiber || - fiber === trackedPathMatchFiber.alternate - ) { - setTrackedPath(null); - } + setTrackedPath(null); } const id = fiberInstance.id; @@ -2386,6 +2381,14 @@ export function attach( traceNearestHostComponentUpdate: boolean, virtualLevel: number, // the nth level of virtual instances ): void { + // If we have the tree selection from previous reload, try to match this Instance. + // Also remember whether to do the same for siblings. + const mightSiblingsBeOnTrackedPath = + updateVirtualTrackedPathStateBeforeMount( + virtualInstance, + reconcilingParent, + ); + const stashedParent = reconcilingParent; const stashedPrevious = previouslyReconciledSibling; const stashedRemaining = remainingReconcilingChildren; @@ -2406,13 +2409,16 @@ export function attach( reconcilingParent = stashedParent; previouslyReconciledSibling = stashedPrevious; remainingReconcilingChildren = stashedRemaining; + updateTrackedPathStateAfterMount(mightSiblingsBeOnTrackedPath); } } function recordVirtualUnmount(instance: VirtualInstance) { - if (trackedPathMatchFiber !== null) { + if (trackedPathMatchInstance === instance) { // We're in the process of trying to restore previous selection. - // TODO: Handle virtual instances on the tracked path. + // If this fiber matched but is being unmounted, there's no use trying. + // Reset the state so we don't keep holding onto it. + setTrackedPath(null); } const id = instance.id; @@ -2521,17 +2527,20 @@ export function attach( debug('mountFiberRecursively()', fiber, reconcilingParent); } - // If we have the tree selection from previous reload, try to match this Fiber. - // Also remember whether to do the same for siblings. - const mightSiblingsBeOnTrackedPath = - updateTrackedPathStateBeforeMount(fiber); - const shouldIncludeInTree = !shouldFilterFiber(fiber); let newInstance = null; if (shouldIncludeInTree) { newInstance = recordMount(fiber, reconcilingParent); insertChild(newInstance); } + + // If we have the tree selection from previous reload, try to match this Fiber. + // Also remember whether to do the same for siblings. + const mightSiblingsBeOnTrackedPath = updateTrackedPathStateBeforeMount( + fiber, + newInstance, + ); + const stashedParent = reconcilingParent; const stashedPrevious = previouslyReconciledSibling; const stashedRemaining = remainingReconcilingChildren; @@ -2570,14 +2579,15 @@ export function attach( const fallbackChildFragment = primaryChildFragment ? primaryChildFragment.sibling : null; - const fallbackChild = fallbackChildFragment - ? fallbackChildFragment.child - : null; - if (fallbackChild !== null) { - mountChildrenRecursively( - fallbackChild, - traceNearestHostComponentUpdate, - ); + if (fallbackChildFragment) { + const fallbackChild = fallbackChildFragment.child; + if (fallbackChild !== null) { + updateTrackedPathStateBeforeMount(fallbackChildFragment, null); + mountChildrenRecursively( + fallbackChild, + traceNearestHostComponentUpdate, + ); + } } } else { let primaryChild: Fiber | null = null; @@ -2587,6 +2597,7 @@ export function attach( primaryChild = fiber.child; } else if (fiber.child !== null) { primaryChild = fiber.child.child; + updateTrackedPathStateBeforeMount(fiber.child, null); } if (primaryChild !== null) { mountChildrenRecursively( @@ -5262,13 +5273,15 @@ export function attach( // Remember if we're trying to restore the selection after reload. // In that case, we'll do some extra checks for matching mounts. let trackedPath: Array | null = null; - let trackedPathMatchFiber: Fiber | null = null; + let trackedPathMatchFiber: Fiber | null = null; // This is the deepest unfiltered match of a Fiber. + let trackedPathMatchInstance: DevToolsInstance | null = null; // This is the deepest matched filtered Instance. let trackedPathMatchDepth = -1; let mightBeOnTrackedPath = false; function setTrackedPath(path: Array | null) { if (path === null) { trackedPathMatchFiber = null; + trackedPathMatchInstance = null; trackedPathMatchDepth = -1; mightBeOnTrackedPath = false; } @@ -5278,7 +5291,10 @@ export function attach( // We call this before traversing a new mount. // It remembers whether this Fiber is the next best match for tracked path. // The return value signals whether we should keep matching siblings or not. - function updateTrackedPathStateBeforeMount(fiber: Fiber): boolean { + function updateTrackedPathStateBeforeMount( + fiber: Fiber, + fiberInstance: null | FiberInstance, + ): boolean { if (trackedPath === null || !mightBeOnTrackedPath) { // Fast path: there's nothing to track so do nothing and ignore siblings. return false; @@ -5306,6 +5322,9 @@ export function attach( ) { // We have our next match. trackedPathMatchFiber = fiber; + if (fiberInstance !== null) { + trackedPathMatchInstance = fiberInstance; + } trackedPathMatchDepth++; // Are we out of frames to match? // $FlowFixMe[incompatible-use] found when upgrading Flow @@ -5322,6 +5341,11 @@ export function attach( return false; } } + if (trackedPathMatchFiber === null && fiberInstance === null) { + // We're now looking for a Virtual Instance. It might be inside filtered Fibers + // so we keep looking below. + return true; + } // This Fiber's parent is on the path, but this Fiber itself isn't. // There's no need to check its children--they won't be on the path either. mightBeOnTrackedPath = false; @@ -5329,6 +5353,57 @@ export function attach( return true; } + function updateVirtualTrackedPathStateBeforeMount( + virtualInstance: VirtualInstance, + parentInstance: null | DevToolsInstance, + ): boolean { + if (trackedPath === null || !mightBeOnTrackedPath) { + // Fast path: there's nothing to track so do nothing and ignore siblings. + return false; + } + // Check if we've matched our nearest unfiltered parent so far. + if (trackedPathMatchInstance === parentInstance) { + const actualFrame = getVirtualPathFrame(virtualInstance); + // $FlowFixMe[incompatible-use] found when upgrading Flow + const expectedFrame = trackedPath[trackedPathMatchDepth + 1]; + if (expectedFrame === undefined) { + throw new Error('Expected to see a frame at the next depth.'); + } + if ( + actualFrame.index === expectedFrame.index && + actualFrame.key === expectedFrame.key && + actualFrame.displayName === expectedFrame.displayName + ) { + // We have our next match. + trackedPathMatchFiber = null; // Don't bother looking in Fibers anymore. We're deeper now. + trackedPathMatchInstance = virtualInstance; + trackedPathMatchDepth++; + // Are we out of frames to match? + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (trackedPathMatchDepth === trackedPath.length - 1) { + // There's nothing that can possibly match afterwards. + // Don't check the children. + mightBeOnTrackedPath = false; + } else { + // Check the children, as they might reveal the next match. + mightBeOnTrackedPath = true; + } + // In either case, since we have a match, we don't need + // to check the siblings. They'll never match. + return false; + } + } + if (trackedPathMatchFiber !== null) { + // We're still looking for a Fiber which might be underneath this instance. + return true; + } + // This Instance's parent is on the path, but this Instance itself isn't. + // There's no need to check its children--they won't be on the path either. + mightBeOnTrackedPath = false; + // However, one of its siblings may be on the path so keep searching. + return true; + } + function updateTrackedPathStateAfterMount( mightSiblingsBeOnTrackedPath: boolean, ) { @@ -5428,6 +5503,14 @@ export function attach( }; } + function getVirtualPathFrame(virtualInstance: VirtualInstance): PathFrame { + return { + displayName: virtualInstance.data.name || '', + key: virtualInstance.data.key == null ? null : virtualInstance.data.key, + index: -1, // We use -1 to indicate that this is a virtual path frame. + }; + } + // Produces a serializable representation that does a best effort // of identifying a particular Fiber between page reloads. // The return path will contain Fibers that are "invisible" to the store @@ -5437,13 +5520,20 @@ export function attach( if (devtoolsInstance === undefined) { return null; } - if (devtoolsInstance.kind !== FIBER_INSTANCE) { - // TODO: Handle VirtualInstance. - return null; - } - let fiber: null | Fiber = devtoolsInstance.data; const keyPath = []; + + let inst: DevToolsInstance = devtoolsInstance; + while (inst.kind === VIRTUAL_INSTANCE) { + keyPath.push(getVirtualPathFrame(inst)); + if (inst.parent === null) { + // This is a bug but non-essential. We should've found a root instance. + return null; + } + inst = inst.parent; + } + + let fiber: null | Fiber = inst.data; while (fiber !== null) { // $FlowFixMe[incompatible-call] found when upgrading Flow keyPath.push(getPathFrame(fiber)); @@ -5459,20 +5549,12 @@ export function attach( // Nothing to match. return null; } - if (trackedPathMatchFiber === null) { + if (trackedPathMatchInstance === null) { // We didn't find anything. return null; } - // Find the closest Fiber store is aware of. - let fiber: null | Fiber = trackedPathMatchFiber; - while (fiber !== null && shouldFilterFiber(fiber)) { - fiber = fiber.return; - } - if (fiber === null) { - return null; - } return { - id: getFiberIDThrows(fiber), + id: trackedPathMatchInstance.id, // $FlowFixMe[incompatible-use] found when upgrading Flow isFullMatch: trackedPathMatchDepth === trackedPath.length - 1, }; From 61739a8a0fd23adf18336d96f9c307a1cd897354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 29 Aug 2024 12:49:30 -0400 Subject: [PATCH 080/426] [DevTools] Filter Server Components (#30839) Support filtering Virtual Instances with existing filters. Server Components are considered "Functions". In a follow up I'll a new filter for "Environment" which will let you filter by Client vs Server (and more). --- .../src/backend/fiber/renderer.js | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 0a19c79718c74..08158086def33 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -1216,7 +1216,26 @@ export function attach( } function shouldFilterVirtual(data: ReactComponentInfo): boolean { - // TODO: Apply filters to VirtualInstances. + // For purposes of filtering Server Components are always Function Components. + // Environment will be used to filter Server vs Client. + // Technically they can be forwardRef and memo too but those filters will go away + // as those become just plain user space function components like any HoC. + if (hideElementsWithTypes.has(ElementTypeFunction)) { + return true; + } + + if (hideElementsWithDisplayNames.size > 0) { + const displayName = data.name; + if (displayName != null) { + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const displayNameRegExp of hideElementsWithDisplayNames) { + if (displayNameRegExp.test(displayName)) { + return true; + } + } + } + } + return false; } @@ -2446,6 +2465,10 @@ export function attach( continue; } const componentInfo: ReactComponentInfo = (debugEntry: any); + if (shouldFilterVirtual(componentInfo)) { + // Skip. + continue; + } if (level === virtualLevel) { if ( previousVirtualInstance === null || @@ -2864,6 +2887,9 @@ export function attach( continue; } const componentInfo: ReactComponentInfo = (debugEntry: any); + if (shouldFilterVirtual(componentInfo)) { + continue; + } if (level === virtualLevel) { if ( previousVirtualInstance === null || @@ -3686,19 +3712,16 @@ export function attach( } // We couldn't use this Fiber but we might have a VirtualInstance // that is the nearest unfiltered instance. - let parentInstance = fiberInstance.parent; - while (parentInstance !== null) { - if (parentInstance.kind === FIBER_INSTANCE) { - // If we find a parent Fiber, it might not be the nearest parent - // so we break out and continue walking the Fiber tree instead. - break; - } else { - if (!shouldFilterVirtual(parentInstance.data)) { - return parentInstance.id; - } - } - parentInstance = parentInstance.parent; + const parentInstance = fiberInstance.parent; + if ( + parentInstance !== null && + parentInstance.kind === VIRTUAL_INSTANCE + ) { + // Virtual Instances only exist if they're unfiltered. + return parentInstance.id; } + // If we find a parent Fiber, it might not be the nearest parent + // so we break out and continue walking the Fiber tree instead. } fiber = fiber.return; } From 071dd00366b3accb649e3f5978454e993e0b11aa Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Thu, 29 Aug 2024 22:40:41 -0700 Subject: [PATCH 081/426] [compiler] Errors in earlier functions dont stop subsequent compilation Errors in an earlier component/hook shouldn't stop later components from compiling. ghstack-source-id: 6e04a5bb2e2045303cbddad6d6d4bd38d5f7990b Pull Request resolved: https://github.com/facebook/react/pull/30844 --- .../src/Entrypoint/Program.ts | 13 ++--- .../src/Entrypoint/Suppression.ts | 10 ++-- ...alid-unclosed-eslint-suppression.expect.md | 2 - ...iple-components-first-is-invalid.expect.md | 50 +++++++++++++++++++ .../multiple-components-first-is-invalid.js | 13 +++++ ...suppression-skips-all-components.expect.md | 39 +++++++++++++++ ...eslint-suppression-skips-all-components.js | 12 +++++ 7 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index 979e9f88d1b57..c2c7d8d640846 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -310,8 +310,6 @@ export function compileProgram( pass.opts.eslintSuppressionRules ?? DEFAULT_ESLINT_SUPPRESSIONS, pass.opts.flowSuppressions, ); - const lintError = suppressionsToCompilerError(suppressions); - let hasCriticalError = lintError != null; const queue: Array<{ kind: 'original' | 'outlined'; fn: BabelFn; @@ -385,7 +383,8 @@ export function compileProgram( ); } - if (lintError != null) { + let compiledFn: CodegenFunction; + try { /** * Note that Babel does not attach comment nodes to nodes; they are dangling off of the * Program node itself. We need to figure out whether an eslint suppression range @@ -396,16 +395,15 @@ export function compileProgram( fn, ); if (suppressionsInFunction.length > 0) { + const lintError = suppressionsToCompilerError(suppressionsInFunction); if (optOutDirectives.length > 0) { logError(lintError, pass, fn.node.loc ?? null); } else { handleError(lintError, pass, fn.node.loc ?? null); } + return null; } - } - let compiledFn: CodegenFunction; - try { compiledFn = compileFn( fn, environment, @@ -436,7 +434,6 @@ export function compileProgram( return null; } } - hasCriticalError ||= isCriticalError(err); handleError(err, pass, fn.node.loc ?? null); return null; } @@ -470,7 +467,7 @@ export function compileProgram( return null; } - if (!pass.opts.noEmit && !hasCriticalError) { + if (!pass.opts.noEmit) { return compiledFn; } return null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts index 71341989a7592..4d0369f5210ca 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Suppression.ts @@ -14,6 +14,7 @@ import { ErrorSeverity, } from '../CompilerError'; import {assertExhaustive} from '../Utils/utils'; +import {GeneratedSource} from '../HIR'; /** * Captures the start and end range of a pair of eslint-disable ... eslint-enable comments. In the @@ -148,10 +149,11 @@ export function findProgramSuppressions( export function suppressionsToCompilerError( suppressionRanges: Array, -): CompilerError | null { - if (suppressionRanges.length === 0) { - return null; - } +): CompilerError { + CompilerError.invariant(suppressionRanges.length !== 0, { + reason: `Expected at least suppression comment source range`, + loc: GeneratedSource, + }); const error = new CompilerError(); for (const suppressionRange of suppressionRanges) { if ( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md index b81dadf409301..9f8e15592df6f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-unclosed-eslint-suppression.expect.md @@ -39,8 +39,6 @@ function CrimesAgainstReact() { 1 | // Note: Everything below this is sketchy > 2 | /* eslint-disable react-hooks/rules-of-hooks */ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ InvalidReact: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled. React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. eslint-disable react-hooks/rules-of-hooks (2:2) - -InvalidReact: React Compiler has skipped optimizing this component because one or more React ESLint rules were disabled. React Compiler only works when your components follow all the rules of React, disabling them may result in unexpected or incorrect behavior. eslint-disable-next-line react-hooks/rules-of-hooks (25:25) 3 | function lowercasecomponent() { 4 | 'use forget'; 5 | const x = []; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.expect.md new file mode 100644 index 0000000000000..3224997b40343 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +// @panicThreshold(none) +import {useHook} from 'shared-runtime'; + +function InvalidComponent(props) { + if (props.cond) { + useHook(); + } + return
Hello World!
; +} + +function ValidComponent(props) { + return
{props.greeting}
; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @panicThreshold(none) +import { useHook } from "shared-runtime"; + +function InvalidComponent(props) { + if (props.cond) { + useHook(); + } + return
Hello World!
; +} + +function ValidComponent(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.greeting) { + t0 =
{props.greeting}
; + $[0] = props.greeting; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.js new file mode 100644 index 0000000000000..6a3d52c86406a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/multiple-components-first-is-invalid.js @@ -0,0 +1,13 @@ +// @panicThreshold(none) +import {useHook} from 'shared-runtime'; + +function InvalidComponent(props) { + if (props.cond) { + useHook(); + } + return
Hello World!
; +} + +function ValidComponent(props) { + return
{props.greeting}
; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.expect.md new file mode 100644 index 0000000000000..f0c6bce34222e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.expect.md @@ -0,0 +1,39 @@ + +## Input + +```javascript +// @panicThreshold(none) + +// unclosed disable rule should affect all components +/* eslint-disable react-hooks/rules-of-hooks */ + +function ValidComponent1(props) { + return
Hello World!
; +} + +function ValidComponent2(props) { + return
{props.greeting}
; +} + +``` + +## Code + +```javascript +// @panicThreshold(none) + +// unclosed disable rule should affect all components +/* eslint-disable react-hooks/rules-of-hooks */ + +function ValidComponent1(props) { + return
Hello World!
; +} + +function ValidComponent2(props) { + return
{props.greeting}
; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.js new file mode 100644 index 0000000000000..121f10041821f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unclosed-eslint-suppression-skips-all-components.js @@ -0,0 +1,12 @@ +// @panicThreshold(none) + +// unclosed disable rule should affect all components +/* eslint-disable react-hooks/rules-of-hooks */ + +function ValidComponent1(props) { + return
Hello World!
; +} + +function ValidComponent2(props) { + return
{props.greeting}
; +} From 394e75d9a9af26dc00074f2b8c2978d8c2dfbbb9 Mon Sep 17 00:00:00 2001 From: Rune Botten Date: Fri, 30 Aug 2024 02:34:27 -0700 Subject: [PATCH 082/426] [DevTools] Increase max payload for websocket in standalone app (#30848) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary When debugging applications that are experiencing runaway re-rendering, it is helpful to profile them in the React Developer Tools. Unfortunately there is a size limit on the captured profile which can make them impossible to inspect or save. The limitations I have found are in `postMessage` for the Chrome extension and in the `ws` websocket server for the standalone app. Profiling an app that produces a large profile artifact will simply show that no profiling data was captured and output an error in the console, here shown for the standalone app: ```text standalone.js:92 [React DevTools] Error with websocket connection i {target: H, type: 'error', message: 'Max payload size exceeded', error: RangeError: Max payload size exceeded at e.exports.haveLength (/Users/rune/.npm/_npx/8ea6ac5c50…}error: RangeError: Max payload size exceeded ``` This change simply increases the max payload of the websocket server in the standalone app so that larger profiles may be captured and inspected. ## How did you test this change? I verified that I could capture and inspect profiling data that previously exceeded the default limitation for a particular app --- packages/react-devtools-core/src/standalone.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-devtools-core/src/standalone.js b/packages/react-devtools-core/src/standalone.js index 541efa0d37e96..22aea529dd8e3 100644 --- a/packages/react-devtools-core/src/standalone.js +++ b/packages/react-devtools-core/src/standalone.js @@ -329,7 +329,7 @@ function startServer( const httpServer = useHttps ? require('https').createServer(httpsOptions) : require('http').createServer(); - const server = new Server({server: httpServer}); + const server = new Server({server: httpServer, maxPayload: 1e9}); let connected: WebSocket | null = null; server.on('connection', (socket: WebSocket) => { if (connected !== null) { From 8308d2f1fe90ec0b5a5cde147b97c6e78581710a Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Fri, 30 Aug 2024 10:34:52 +0100 Subject: [PATCH 083/426] fix[react-devtools/ReactDebugHooks]: support unstable prefixes in hooks and useContextWithBailout (#30837) Related - https://github.com/facebook/react/pull/30407. This is experimental-only and FB-only hook. Without these changes, inspecting an element that is using this hook will throw an error, because this hook is missing in Dispatcher implementation from React DevTools, which overrides the original one to build the hook tree. ![Screenshot 2024-08-28 at 18 42 55](https://github.com/user-attachments/assets/e3bccb92-74fb-4e4a-8181-03d13f8512c0) One nice thing from it is that in case of any potential regressions related to this experiment, we can quickly triage which implementation of `useContext` is used by inspecting an element in React DevTools. Ideally, I should've added some component that is using this hook to `react-devtools-shell`, so it can be manually tested, but I can't do it without rewriting the infra for it. This is because this hook is only available from fb-www builds, and not experimental. --- .../react-debug-tools/src/ReactDebugHooks.js | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index edbef05e259d1..c54e591321dee 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -20,6 +20,7 @@ import type { Dependencies, Fiber, Dispatcher as DispatcherType, + ContextDependencyWithSelect, } from 'react-reconciler/src/ReactInternalTypes'; import type {TransitionStatus} from 'react-reconciler/src/ReactFiberConfig'; @@ -37,7 +38,6 @@ import { REACT_CONTEXT_TYPE, } from 'shared/ReactSymbols'; import hasOwnProperty from 'shared/hasOwnProperty'; -import type {ContextDependencyWithSelect} from '../../react-reconciler/src/ReactInternalTypes'; type CurrentDispatcherRef = typeof ReactSharedInternals; @@ -76,6 +76,13 @@ function getPrimitiveStackCache(): Map> { try { // Use all hooks here to add them to the hook log. Dispatcher.useContext(({_currentValue: null}: any)); + if (typeof Dispatcher.unstable_useContextWithBailout === 'function') { + // This type check is for Flow only. + Dispatcher.unstable_useContextWithBailout( + ({_currentValue: null}: any), + null, + ); + } Dispatcher.useState(null); Dispatcher.useReducer((s: mixed, a: mixed) => s, null); Dispatcher.useRef(null); @@ -280,6 +287,22 @@ function useContext(context: ReactContext): T { return value; } +function unstable_useContextWithBailout( + context: ReactContext, + select: (T => Array) | null, +): T { + const value = readContext(context); + hookLog.push({ + displayName: context.displayName || null, + primitive: 'ContextWithBailout', + stackError: new Error(), + value: value, + debugInfo: null, + dispatcherHookName: 'ContextWithBailout', + }); + return value; +} + function useState( initialState: (() => S) | S, ): [S, Dispatch>] { @@ -753,6 +776,7 @@ const Dispatcher: DispatcherType = { useCacheRefresh, useCallback, useContext, + unstable_useContextWithBailout, useEffect, useImperativeHandle, useDebugValue, @@ -954,6 +978,11 @@ function parseHookName(functionName: void | string): string { } else { startIndex += 1; } + + if (functionName.slice(startIndex).startsWith('unstable_')) { + startIndex += 'unstable_'.length; + } + if (functionName.slice(startIndex, startIndex + 3) === 'use') { if (functionName.length - startIndex === 3) { return 'Use'; From e56f4ae38d118168e0561f1b86ecbdef592138e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 30 Aug 2024 10:05:19 -0400 Subject: [PATCH 084/426] [DevTools] Support secondary environment name when it changes (#30842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently support the Environment Name change within a Component. #29867 If this happens, we give it two HoCs. The problem with this is that we only show one followed by `+1` in the list. Before: Screenshot 2024-08-28 at 6 50 31 PM After: Screenshot 2024-08-28 at 7 16 21 PM I could potentially instead badge this case as `A/B` in a single badge. --- .../src/backend/fiber/renderer.js | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 08158086def33..47cb12bf17ae0 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -7,7 +7,7 @@ * @flow */ -import type {ReactComponentInfo} from 'shared/ReactTypes'; +import type {ReactComponentInfo, ReactDebugInfo} from 'shared/ReactTypes'; import { ComponentFilterDisplayName, @@ -2226,6 +2226,7 @@ export function attach( function recordVirtualMount( instance: VirtualInstance, parentInstance: DevToolsInstance | null, + secondaryEnv: null | string, ): void { const id = instance.id; @@ -2239,6 +2240,9 @@ export function attach( let displayName = componentInfo.name || ''; if (typeof env === 'string') { // We model environment as an HoC name for now. + if (secondaryEnv !== null) { + displayName = secondaryEnv + '(' + displayName + ')'; + } displayName = env + '(' + displayName + ')'; } const elementType = ElementTypeVirtual; @@ -2444,6 +2448,25 @@ export function attach( pendingRealUnmountedIDs.push(id); } + function getSecondaryEnvironmentName( + debugInfo: ?ReactDebugInfo, + index: number, + ): null | string { + if (debugInfo != null) { + const componentInfo: ReactComponentInfo = (debugInfo[index]: any); + for (let i = index + 1; i < debugInfo.length; i++) { + const debugEntry = debugInfo[i]; + if (typeof debugEntry.env === 'string') { + // If the next environment is different then this component was the boundary + // and it changed before entering the next component. So we assign this + // component a secondary environment. + return componentInfo.env !== debugEntry.env ? debugEntry.env : null; + } + } + } + return null; + } + function mountVirtualChildrenRecursively( firstChild: Fiber, lastChild: null | Fiber, // non-inclusive @@ -2464,6 +2487,7 @@ export function attach( // Not a Component. Some other Debug Info. continue; } + // Scan up until the next Component to see if this component changed environment. const componentInfo: ReactComponentInfo = (debugEntry: any); if (shouldFilterVirtual(componentInfo)) { // Skip. @@ -2487,7 +2511,15 @@ export function attach( ); } previousVirtualInstance = createVirtualInstance(componentInfo); - recordVirtualMount(previousVirtualInstance, reconcilingParent); + const secondaryEnv = getSecondaryEnvironmentName( + fiber._debugInfo, + i, + ); + recordVirtualMount( + previousVirtualInstance, + reconcilingParent, + secondaryEnv, + ); insertChild(previousVirtualInstance); previousVirtualInstanceFirstFiber = fiber; } @@ -2951,7 +2983,15 @@ export function attach( } else { // Otherwise we create a new instance. const newVirtualInstance = createVirtualInstance(componentInfo); - recordVirtualMount(newVirtualInstance, reconcilingParent); + const secondaryEnv = getSecondaryEnvironmentName( + nextChild._debugInfo, + i, + ); + recordVirtualMount( + newVirtualInstance, + reconcilingParent, + secondaryEnv, + ); insertChild(newVirtualInstance); previousVirtualInstance = newVirtualInstance; previousVirtualInstanceWasMount = true; From 4f604941569d2e8947ce1460a0b2997e835f37b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 30 Aug 2024 15:11:57 -0400 Subject: [PATCH 085/426] [Flight] Ship DEV-only enableServerComponentLogs flag in Stable/Canary (#30847) To recap. This only affects DEV and RSC. It patches console on the server in DEV (similar to how React DevTools already does and what we did for the double logging). Then replays those logs with a `[Server]` badge on the client so you don't need a server terminal open. This has been on for over 6 months now in our experimental channel and we've had a lot of coverage in Next.js due to various experimental flags like taint and ppr. It's non-invasive in that even if something throws we just serialize that as an unknown value. The main feedback we've gotten was: - The serialization depth wasn't deep enough which I addressed in #30294 and haven't really had any issues since. This could still be an issue or the inverse that you serialize too many logs that are also too deep. This is not so much an issue with intentional logging and things like accidental errors don't typically have unbounded arguments (e.g. React errors are always string arguments). The ideal would be some way to retain objects and then load them on-demand but that needs more plumbing. Which can be later. - The other was that double logging on the server is annoying if the same terminal does both the RSC render and SSR render which was addressed in #30207. It is now off by default in node/edge-builds of the client, on by default in browser builds. With the `replayConsole` option to either opt-in or out. We've reached a good spot now I think. These are better with `enableOwnerStacks` but that's a separate track and not needed. The only thing to document here, other than maybe that we're doing it, is the `replayConsole` option but that's part of the RSC renderers that themselves are not documented so nowhere to document it. --- packages/shared/ReactFeatureFlags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 673ff9d7e8450..10084be3cf2ef 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -134,7 +134,7 @@ export const alwaysThrottleRetries = true; export const passChildrenWhenCloningPersistedNodes = false; -export const enableServerComponentLogs = __EXPERIMENTAL__; +export const enableServerComponentLogs = true; /** * Enables a new Fiber flag used in persisted mode to reduce the number From 04ec50efa941a7f07e8231a87e72d6d851948b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 3 Sep 2024 12:29:15 -0400 Subject: [PATCH 086/426] [DevTools] Add Filtering of Environment Names (#30850) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacked on #30842. This adds a filter to be able to exclude Components from a certain environment. Default to Client or Server. The available options are computed into a dropdown based on the names that are currently used on the page (or an option that were previously used). In addition to the hardcoded "Client". Meaning that if you have Server Components on the page you see "Server" or "Client" as possible options but it can be anything if there are multiple RSC environments on the page. "Client" in this case means Function and Class Components in Fiber - excluding built-ins. If a Server Component has two environments (primary and secondary) then both have to be filtered to exclude it. We don't show the option at all if there are no Server Components used in the page to avoid confusing existing users that are just using Client Components and wouldn't know the difference between Server vs Client. Screenshot 2024-08-30 at 12 56 42 AM --- .../src/__tests__/utils.js | 13 +++ .../src/backend/agent.js | 19 ++++ .../src/backend/fiber/renderer.js | 80 +++++++++++++--- .../src/backend/legacy/renderer.js | 6 ++ .../src/backend/types.js | 1 + packages/react-devtools-shared/src/bridge.js | 2 + .../views/Settings/ComponentsSettings.js | 93 ++++++++++++++++++- .../devtools/views/Settings/SettingsModal.js | 5 +- .../views/Settings/SettingsModalContext.js | 47 ++++++++-- .../src/frontend/types.js | 13 ++- 10 files changed, 253 insertions(+), 26 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/utils.js b/packages/react-devtools-shared/src/__tests__/utils.js index 4a42cf2703ffb..c22ac6e05dc11 100644 --- a/packages/react-devtools-shared/src/__tests__/utils.js +++ b/packages/react-devtools-shared/src/__tests__/utils.js @@ -284,6 +284,19 @@ export function createHOCFilter(isEnabled: boolean = true) { }; } +export function createEnvironmentNameFilter( + env: string, + isEnabled: boolean = true, +) { + const Types = require('react-devtools-shared/src/frontend/types'); + return { + type: Types.ComponentFilterEnvironmentName, + isEnabled, + isValid: true, + value: env, + }; +} + export function createElementTypeFilter( elementType: ElementType, isEnabled: boolean = true, diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index a71b259441e98..9de4115b21d97 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -220,6 +220,7 @@ export default class Agent extends EventEmitter<{ this.updateConsolePatchSettings, ); bridge.addListener('updateComponentFilters', this.updateComponentFilters); + bridge.addListener('getEnvironmentNames', this.getEnvironmentNames); // Temporarily support older standalone front-ends sending commands to newer embedded backends. // We do this because React Native embeds the React DevTools backend, @@ -814,6 +815,24 @@ export default class Agent extends EventEmitter<{ } }; + getEnvironmentNames: () => void = () => { + let accumulatedNames = null; + for (const rendererID in this._rendererInterfaces) { + const renderer = this._rendererInterfaces[+rendererID]; + const names = renderer.getEnvironmentNames(); + if (accumulatedNames === null) { + accumulatedNames = names; + } else { + for (let i = 0; i < names.length; i++) { + if (accumulatedNames.indexOf(names[i]) === -1) { + accumulatedNames.push(names[i]); + } + } + } + } + this._bridge.send('environmentNames', accumulatedNames || []); + }; + onTraceUpdates: (nodes: Set) => void = nodes => { this.emit('traceUpdates', nodes); }; diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 47cb12bf17ae0..7960f68fb54a3 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -14,6 +14,7 @@ import { ComponentFilterElementType, ComponentFilterHOC, ComponentFilterLocation, + ComponentFilterEnvironmentName, ElementTypeClass, ElementTypeContext, ElementTypeFunction, @@ -721,6 +722,11 @@ export function getInternalReactConstants(version: string): { }; } +// All environment names we've seen so far. This lets us create a list of filters to apply. +// This should ideally include env of filtered Components too so that you can add those as +// filters at the same time as removing some other filter. +const knownEnvironmentNames: Set = new Set(); + // Map of one or more Fibers in a pair to their unique id number. // We track both Fibers to support Fast Refresh, // which may forcefully replace one of the pair as part of hot reloading. @@ -1099,6 +1105,7 @@ export function attach( const hideElementsWithDisplayNames: Set = new Set(); const hideElementsWithPaths: Set = new Set(); const hideElementsWithTypes: Set = new Set(); + const hideElementsWithEnvs: Set = new Set(); // Highlight updates let traceUpdatesEnabled: boolean = false; @@ -1108,6 +1115,7 @@ export function attach( hideElementsWithTypes.clear(); hideElementsWithDisplayNames.clear(); hideElementsWithPaths.clear(); + hideElementsWithEnvs.clear(); componentFilters.forEach(componentFilter => { if (!componentFilter.isEnabled) { @@ -1133,6 +1141,9 @@ export function attach( case ComponentFilterHOC: hideElementsWithDisplayNames.add(new RegExp('\\(')); break; + case ComponentFilterEnvironmentName: + hideElementsWithEnvs.add(componentFilter.value); + break; default: console.warn( `Invalid component filter type "${componentFilter.type}"`, @@ -1215,7 +1226,14 @@ export function attach( flushPendingEvents(); } - function shouldFilterVirtual(data: ReactComponentInfo): boolean { + function getEnvironmentNames(): Array { + return Array.from(knownEnvironmentNames); + } + + function shouldFilterVirtual( + data: ReactComponentInfo, + secondaryEnv: null | string, + ): boolean { // For purposes of filtering Server Components are always Function Components. // Environment will be used to filter Server vs Client. // Technically they can be forwardRef and memo too but those filters will go away @@ -1236,6 +1254,14 @@ export function attach( } } + if ( + (data.env == null || hideElementsWithEnvs.has(data.env)) && + (secondaryEnv === null || hideElementsWithEnvs.has(secondaryEnv)) + ) { + // If a Component has two environments, you have to filter both for it not to appear. + return true; + } + return false; } @@ -1294,6 +1320,26 @@ export function attach( } } + if (hideElementsWithEnvs.has('Client')) { + // If we're filtering out the Client environment we should filter out all + // "Client Components". Technically that also includes the built-ins but + // since that doesn't actually include any additional code loading it's + // useful to not filter out the built-ins. Those can be filtered separately. + // There's no other way to filter out just Function components on the Client. + // Therefore, this only filters Class and Function components. + switch (tag) { + case ClassComponent: + case IncompleteClassComponent: + case IncompleteFunctionComponent: + case FunctionComponent: + case IndeterminateComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + return true; + } + } + /* DISABLED: https://github.com/facebook/react/pull/28417 if (hideElementsWithPaths.size > 0) { const source = getSourceForFiber(fiber); @@ -2489,7 +2535,14 @@ export function attach( } // Scan up until the next Component to see if this component changed environment. const componentInfo: ReactComponentInfo = (debugEntry: any); - if (shouldFilterVirtual(componentInfo)) { + const secondaryEnv = getSecondaryEnvironmentName(fiber._debugInfo, i); + if (componentInfo.env != null) { + knownEnvironmentNames.add(componentInfo.env); + } + if (secondaryEnv !== null) { + knownEnvironmentNames.add(secondaryEnv); + } + if (shouldFilterVirtual(componentInfo, secondaryEnv)) { // Skip. continue; } @@ -2511,10 +2564,6 @@ export function attach( ); } previousVirtualInstance = createVirtualInstance(componentInfo); - const secondaryEnv = getSecondaryEnvironmentName( - fiber._debugInfo, - i, - ); recordVirtualMount( previousVirtualInstance, reconcilingParent, @@ -2919,7 +2968,17 @@ export function attach( continue; } const componentInfo: ReactComponentInfo = (debugEntry: any); - if (shouldFilterVirtual(componentInfo)) { + const secondaryEnv = getSecondaryEnvironmentName( + nextChild._debugInfo, + i, + ); + if (componentInfo.env != null) { + knownEnvironmentNames.add(componentInfo.env); + } + if (secondaryEnv !== null) { + knownEnvironmentNames.add(secondaryEnv); + } + if (shouldFilterVirtual(componentInfo, secondaryEnv)) { continue; } if (level === virtualLevel) { @@ -2983,10 +3042,6 @@ export function attach( } else { // Otherwise we create a new instance. const newVirtualInstance = createVirtualInstance(componentInfo); - const secondaryEnv = getSecondaryEnvironmentName( - nextChild._debugInfo, - i, - ); recordVirtualMount( newVirtualInstance, reconcilingParent, @@ -3925,7 +3980,7 @@ export function attach( owner = ownerFiber._debugOwner; } else { const ownerInfo: ReactComponentInfo = (owner: any); // Refined - if (!shouldFilterVirtual(ownerInfo)) { + if (!shouldFilterVirtual(ownerInfo, null)) { return ownerInfo; } owner = ownerInfo.owner; @@ -5750,5 +5805,6 @@ export function attach( storeAsGlobal, unpatchConsoleForStrictMode, updateComponentFilters, + getEnvironmentNames, }; } diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index 523fbbeba3d8e..ccff5ef07a1b6 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -1078,6 +1078,11 @@ export function attach( // Not implemented. } + function getEnvironmentNames(): Array { + // No RSC support. + return []; + } + function setTraceUpdatesEnabled(enabled: boolean) { // Not implemented. } @@ -1152,5 +1157,6 @@ export function attach( storeAsGlobal, unpatchConsoleForStrictMode, updateComponentFilters, + getEnvironmentNames, }; } diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 41c278d02ebdf..2f1482fb1cbd2 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -416,6 +416,7 @@ export type RendererInterface = { ) => void, unpatchConsoleForStrictMode: () => void, updateComponentFilters: (componentFilters: Array) => void, + getEnvironmentNames: () => Array, // Timeline profiler interface diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index f4da08be6bdbe..1e9b3c222d623 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -189,6 +189,7 @@ export type BackendEvents = { operations: [Array], ownersList: [OwnersList], overrideComponentFilters: [Array], + environmentNames: [Array], profilingData: [ProfilingDataBackend], profilingStatus: [boolean], reloadAppForProfiling: [], @@ -237,6 +238,7 @@ type FrontendEvents = { stopProfiling: [], storeAsGlobal: [StoreAsGlobalParams], updateComponentFilters: [Array], + getEnvironmentNames: [], updateConsolePatchSettings: [ConsolePatchSettings], viewAttributeSource: [ViewAttributeSourceParams], viewElementSource: [ElementAndRendererID], diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js index a2a6a1d681819..33552daa262d8 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js @@ -15,6 +15,7 @@ import { useMemo, useRef, useState, + use, } from 'react'; import { LOCAL_STORAGE_OPEN_IN_EDITOR_URL, @@ -31,6 +32,7 @@ import { ComponentFilterElementType, ComponentFilterHOC, ComponentFilterLocation, + ComponentFilterEnvironmentName, ElementTypeClass, ElementTypeContext, ElementTypeFunction, @@ -52,11 +54,16 @@ import type { ElementType, ElementTypeComponentFilter, RegExpComponentFilter, + EnvironmentNameComponentFilter, } from 'react-devtools-shared/src/frontend/types'; const vscodeFilepath = 'vscode://file/{path}:{line}'; -export default function ComponentsSettings(_: {}): React.Node { +export default function ComponentsSettings({ + environmentNames, +}: { + environmentNames: Promise>, +}): React.Node { const store = useContext(StoreContext); const {parseHookNames, setParseHookNames} = useContext(SettingsContext); @@ -101,6 +108,30 @@ export default function ComponentsSettings(_: {}): React.Node { Array, >(() => [...store.componentFilters]); + const usedEnvironmentNames = use(environmentNames); + + const resolvedEnvironmentNames = useMemo(() => { + const set = new Set(usedEnvironmentNames); + // If there are other filters already specified but are not currently + // on the page, we still allow them as options. + for (let i = 0; i < componentFilters.length; i++) { + const filter = componentFilters[i]; + if (filter.type === ComponentFilterEnvironmentName) { + set.add(filter.value); + } + } + // Client is special and is always available as a default. + if (set.size > 0) { + // Only show any options at all if there's any other option already + // used by a filter or if any environments are used by the page. + // Note that "Client" can have been added above which would mean + // that we should show it as an option regardless if it's the only + // option. + set.add('Client'); + } + return Array.from(set).sort(); + }, [usedEnvironmentNames, componentFilters]); + const addFilter = useCallback(() => { setComponentFilters(prevComponentFilters => { return [ @@ -146,6 +177,13 @@ export default function ComponentsSettings(_: {}): React.Node { isEnabled: componentFilter.isEnabled, isValid: true, }; + } else if (type === ComponentFilterEnvironmentName) { + cloned[index] = { + type: ComponentFilterEnvironmentName, + isEnabled: componentFilter.isEnabled, + isValid: true, + value: 'Client', + }; } } return cloned; @@ -210,6 +248,29 @@ export default function ComponentsSettings(_: {}): React.Node { [], ); + const updateFilterValueEnvironmentName = useCallback( + (componentFilter: ComponentFilter, value: string) => { + if (componentFilter.type !== ComponentFilterEnvironmentName) { + throw Error('Invalid value for environment name filter'); + } + + setComponentFilters(prevComponentFilters => { + const cloned: Array = [...prevComponentFilters]; + if (componentFilter.type === ComponentFilterEnvironmentName) { + const index = prevComponentFilters.indexOf(componentFilter); + if (index >= 0) { + cloned[index] = { + ...componentFilter, + value, + }; + } + } + return cloned; + }); + }, + [], + ); + const removeFilter = useCallback((index: number) => { setComponentFilters(prevComponentFilters => { const cloned: Array = [...prevComponentFilters]; @@ -246,6 +307,11 @@ export default function ComponentsSettings(_: {}): React.Node { ...((cloned[index]: any): BooleanComponentFilter), isEnabled, }; + } else if (componentFilter.type === ComponentFilterEnvironmentName) { + cloned[index] = { + ...((cloned[index]: any): EnvironmentNameComponentFilter), + isEnabled, + }; } } return cloned; @@ -380,10 +446,16 @@ export default function ComponentsSettings(_: {}): React.Node { + {resolvedEnvironmentNames.length > 0 && ( + + )} - {componentFilter.type === ComponentFilterElementType && + {(componentFilter.type === ComponentFilterElementType || + componentFilter.type === ComponentFilterEnvironmentName) && 'equals'} {(componentFilter.type === ComponentFilterLocation || componentFilter.type === ComponentFilterDisplayName) && @@ -428,6 +500,23 @@ export default function ComponentsSettings(_: {}): React.Node { value={componentFilter.value} /> )} + {componentFilter.type === ComponentFilterEnvironmentName && ( + + )} + ))} +
+ ); + }; + + await act(() => { + root.render(); + }); + + newWindow.document.getElementById('a').focus(); + await act(() => { + newWindow.document.getElementById('a').click(); + }); + + expect(newWindow.document.activeElement).not.toBe(newWindow.document.body); + expect(newWindow.document.activeElement.innerHTML).toBe('a'); + }); }); From 5deb78223a269a6cb1706da8ec6aad8c007cab03 Mon Sep 17 00:00:00 2001 From: Hendrik Liebau Date: Fri, 13 Sep 2024 22:33:05 +0200 Subject: [PATCH 141/426] [Flight] Respect `async` flag in client manifest (#30959) In #26624, the ability to mark a client reference module as `async` in the React client manifest was removed because it was not utilized by Webpack, neither in `ReactFlightWebpackPlugin` nor in Next.js. However, some bundlers and frameworks are sophisticated enough to properly handle and identify async ESM modules (e.g., client component modules with top-level `await`), most notably Turbopack in Next.js. Therefore, we need to consider the `async` flag in the client manifest when resolving the client reference metadata on the server. The SSR manifest cannot override this flag, meaning that if a module is async, it must remain async in all client environments. x-ref: https://github.com/vercel/next.js/pull/70022 --- .../__tests__/ReactFlightTurbopackDOM-test.js | 120 ++++++++++++++++++ .../src/__tests__/utils/TurbopackMock.js | 60 +++++++++ ...ReactFlightServerConfigTurbopackBundler.js | 10 +- .../src/shared/ReactFlightImportMetadata.js | 1 + .../src/__tests__/ReactFlightDOM-test.js | 103 +++++++++++++++ .../src/__tests__/utils/WebpackMock.js | 63 +++++++++ .../ReactFlightServerConfigWebpackBundler.js | 10 +- .../src/shared/ReactFlightImportMetadata.js | 1 + 8 files changed, 366 insertions(+), 2 deletions(-) diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js index 0cf2876fedba6..d4fc59b826208 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOM-test.js @@ -20,6 +20,7 @@ global.TextDecoder = require('util').TextDecoder; let act; let use; let clientExports; +let clientExportsESM; let turbopackMap; let Stream; let React; @@ -29,6 +30,7 @@ let ReactServerDOMClient; let Suspense; let ReactServerScheduler; let reactServerAct; +let ErrorBoundary; describe('ReactFlightTurbopackDOM', () => { beforeEach(() => { @@ -49,6 +51,7 @@ describe('ReactFlightTurbopackDOM', () => { const TurbopackMock = require('./utils/TurbopackMock'); clientExports = TurbopackMock.clientExports; + clientExportsESM = TurbopackMock.clientExportsESM; turbopackMap = TurbopackMock.turbopackMap; ReactServerDOMServer = require('react-server-dom-turbopack/server'); @@ -63,6 +66,22 @@ describe('ReactFlightTurbopackDOM', () => { Suspense = React.Suspense; ReactDOMClient = require('react-dom/client'); ReactServerDOMClient = require('react-server-dom-turbopack/client'); + + ErrorBoundary = class extends React.Component { + state = {hasError: false, error: null}; + static getDerivedStateFromError(error) { + return { + hasError: true, + error, + }; + } + render() { + if (this.state.hasError) { + return this.props.fallback(this.state.error); + } + return this.props.children; + } + }; }); async function serverAct(callback) { @@ -220,4 +239,105 @@ describe('ReactFlightTurbopackDOM', () => { }); expect(container.innerHTML).toBe('

Async: Module

'); }); + + it('should unwrap async ESM module references', async () => { + const AsyncModule = Promise.resolve(function AsyncModule({text}) { + return 'Async: ' + text; + }); + + const AsyncModule2 = Promise.resolve({ + exportName: 'Module', + }); + + function Print({response}) { + return

{use(response)}

; + } + + function App({response}) { + return ( + Loading...}> + + + ); + } + + const AsyncModuleRef = await clientExportsESM(AsyncModule); + const AsyncModuleRef2 = await clientExportsESM(AsyncModule2); + + const {writable, readable} = getTestStream(); + const {pipe} = await serverAct(() => + ReactServerDOMServer.renderToPipeableStream( + , + turbopackMap, + ), + ); + pipe(writable); + const response = ReactServerDOMClient.createFromReadableStream(readable); + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + expect(container.innerHTML).toBe('

Async: Module

'); + }); + + it('should error when a bundler uses async ESM modules with createClientModuleProxy', async () => { + const AsyncModule = Promise.resolve(function AsyncModule() { + return 'This should not be rendered'; + }); + + function Print({response}) { + return

{use(response)}

; + } + + function App({response}) { + return ( + ( +

+ {__DEV__ ? error.message + ' + ' : null} + {error.digest} +

+ )}> + Loading...}> + + +
+ ); + } + + const AsyncModuleRef = await clientExportsESM(AsyncModule, { + forceClientModuleProxy: true, + }); + + const {writable, readable} = getTestStream(); + const {pipe} = await serverAct(() => + ReactServerDOMServer.renderToPipeableStream( + , + turbopackMap, + { + onError(error) { + return __DEV__ ? 'a dev digest' : `digest(${error.message})`; + }, + }, + ), + ); + pipe(writable); + const response = ReactServerDOMClient.createFromReadableStream(readable); + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + + const errorMessage = `The module "${Object.keys(turbopackMap).at(0)}" is marked as an async ESM module but was loaded as a CJS proxy. This is probably a bug in the React Server Components bundler.`; + + expect(container.innerHTML).toBe( + __DEV__ + ? `

${errorMessage} + a dev digest

` + : `

digest(${errorMessage})

`, + ); + }); }); diff --git a/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js b/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js index 5ed6fa5357408..2e81d55fa692c 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js +++ b/packages/react-server-dom-turbopack/src/__tests__/utils/TurbopackMock.js @@ -23,6 +23,7 @@ global.__turbopack_require__ = function (id) { }; const Server = require('react-server-dom-turbopack/server'); +const registerClientReference = Server.registerClientReference; const registerServerReference = Server.registerServerReference; const createClientModuleProxy = Server.createClientModuleProxy; @@ -83,6 +84,65 @@ exports.clientExports = function clientExports(moduleExports, chunkUrl) { return createClientModuleProxy(path); }; +exports.clientExportsESM = function clientExportsESM( + moduleExports, + options?: {forceClientModuleProxy?: boolean} = {}, +) { + const chunks = []; + const idx = '' + turbopackModuleIdx++; + turbopackClientModules[idx] = moduleExports; + const path = url.pathToFileURL(idx).href; + + const createClientReferencesForExports = ({exports, async}) => { + turbopackClientMap[path] = { + id: idx, + chunks, + name: '*', + async: true, + }; + + if (options.forceClientModuleProxy) { + return createClientModuleProxy(path); + } + + if (typeof exports === 'object') { + const references = {}; + + for (const name in exports) { + const id = path + '#' + name; + turbopackClientMap[path + '#' + name] = { + id: idx, + chunks, + name: name, + async, + }; + references[name] = registerClientReference(() => {}, id, name); + } + + return references; + } + + return registerClientReference(() => {}, path, '*'); + }; + + if ( + moduleExports && + typeof moduleExports === 'object' && + typeof moduleExports.then === 'function' + ) { + return moduleExports.then( + asyncModuleExports => + createClientReferencesForExports({ + exports: asyncModuleExports, + async: true, + }), + () => {}, + ); + } + + return createClientReferencesForExports({exports: moduleExports}); +}; + // This tests server to server references. There's another case of client to server references. exports.serverExports = function serverExports(moduleExports) { const idx = '' + turbopackModuleIdx++; diff --git a/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js b/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js index d8224aff341dc..219391f8f819e 100644 --- a/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js +++ b/packages/react-server-dom-turbopack/src/server/ReactFlightServerConfigTurbopackBundler.js @@ -71,7 +71,15 @@ export function resolveClientReferenceMetadata( ); } } - if (clientReference.$$async === true) { + if (resolvedModuleData.async === true && clientReference.$$async === true) { + throw new Error( + 'The module "' + + modulePath + + '" is marked as an async ESM module but was loaded as a CJS proxy. ' + + 'This is probably a bug in the React Server Components bundler.', + ); + } + if (resolvedModuleData.async === true || clientReference.$$async === true) { return [resolvedModuleData.id, resolvedModuleData.chunks, name, 1]; } else { return [resolvedModuleData.id, resolvedModuleData.chunks, name]; diff --git a/packages/react-server-dom-turbopack/src/shared/ReactFlightImportMetadata.js b/packages/react-server-dom-turbopack/src/shared/ReactFlightImportMetadata.js index 60460d9c1d6d9..7cfce93deb25a 100644 --- a/packages/react-server-dom-turbopack/src/shared/ReactFlightImportMetadata.js +++ b/packages/react-server-dom-turbopack/src/shared/ReactFlightImportMetadata.js @@ -12,6 +12,7 @@ export type ImportManifestEntry = { // chunks is an array of filenames chunks: Array, name: string, + async?: boolean, }; // This is the parsed shape of the wire format which is why it is diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index 41fc0bfd41088..b59eb05c7b3fb 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -21,6 +21,7 @@ global.TextDecoder = require('util').TextDecoder; let act; let use; let clientExports; +let clientExportsESM; let clientModuleError; let webpackMap; let Stream; @@ -68,6 +69,7 @@ describe('ReactFlightDOM', () => { } const WebpackMock = require('./utils/WebpackMock'); clientExports = WebpackMock.clientExports; + clientExportsESM = WebpackMock.clientExportsESM; clientModuleError = WebpackMock.clientModuleError; webpackMap = WebpackMock.webpackMap; @@ -583,6 +585,107 @@ describe('ReactFlightDOM', () => { expect(container.innerHTML).toBe('

Async Text

'); }); + it('should unwrap async ESM module references', async () => { + const AsyncModule = Promise.resolve(function AsyncModule({text}) { + return 'Async: ' + text; + }); + + const AsyncModule2 = Promise.resolve({ + exportName: 'Module', + }); + + function Print({response}) { + return

{use(response)}

; + } + + function App({response}) { + return ( + Loading...}> + + + ); + } + + const AsyncModuleRef = await clientExportsESM(AsyncModule); + const AsyncModuleRef2 = await clientExportsESM(AsyncModule2); + + const {writable, readable} = getTestStream(); + const {pipe} = await serverAct(() => + ReactServerDOMServer.renderToPipeableStream( + , + webpackMap, + ), + ); + pipe(writable); + const response = ReactServerDOMClient.createFromReadableStream(readable); + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + expect(container.innerHTML).toBe('

Async: Module

'); + }); + + it('should error when a bundler uses async ESM modules with createClientModuleProxy', async () => { + const AsyncModule = Promise.resolve(function AsyncModule() { + return 'This should not be rendered'; + }); + + function Print({response}) { + return

{use(response)}

; + } + + function App({response}) { + return ( + ( +

+ {__DEV__ ? error.message + ' + ' : null} + {error.digest} +

+ )}> + Loading...}> + + +
+ ); + } + + const AsyncModuleRef = await clientExportsESM(AsyncModule, { + forceClientModuleProxy: true, + }); + + const {writable, readable} = getTestStream(); + const {pipe} = await serverAct(() => + ReactServerDOMServer.renderToPipeableStream( + , + webpackMap, + { + onError(error) { + return __DEV__ ? 'a dev digest' : `digest(${error.message})`; + }, + }, + ), + ); + pipe(writable); + const response = ReactServerDOMClient.createFromReadableStream(readable); + + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + + const errorMessage = `The module "${Object.keys(webpackMap).at(0)}" is marked as an async ESM module but was loaded as a CJS proxy. This is probably a bug in the React Server Components bundler.`; + + expect(container.innerHTML).toBe( + __DEV__ + ? `

${errorMessage} + a dev digest

` + : `

digest(${errorMessage})

`, + ); + }); + it('should be able to import a name called "then"', async () => { const thenExports = { then: function then() { diff --git a/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js b/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js index 4527118c1de8b..654bcdc9b6d5c 100644 --- a/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js +++ b/packages/react-server-dom-webpack/src/__tests__/utils/WebpackMock.js @@ -44,6 +44,10 @@ if (previousCompile === nodeCompile) { Module.prototype._compile = previousCompile; +const Server = require('react-server-dom-webpack/server'); +const registerClientReference = Server.registerClientReference; +const createClientModuleProxy = Server.createClientModuleProxy; + exports.webpackMap = webpackClientMap; exports.webpackModules = webpackClientModules; exports.webpackServerMap = webpackServerMap; @@ -126,6 +130,65 @@ exports.clientExports = function clientExports( return mod.exports; }; +exports.clientExportsESM = function clientExportsESM( + moduleExports, + options?: {forceClientModuleProxy?: boolean} = {}, +) { + const chunks = []; + const idx = '' + webpackModuleIdx++; + webpackClientModules[idx] = moduleExports; + const path = url.pathToFileURL(idx).href; + + const createClientReferencesForExports = ({exports, async}) => { + webpackClientMap[path] = { + id: idx, + chunks, + name: '*', + async: true, + }; + + if (options.forceClientModuleProxy) { + return createClientModuleProxy(path); + } + + if (typeof exports === 'object') { + const references = {}; + + for (const name in exports) { + const id = path + '#' + name; + webpackClientMap[path + '#' + name] = { + id: idx, + chunks, + name: name, + async, + }; + references[name] = registerClientReference(() => {}, id, name); + } + + return references; + } + + return registerClientReference(() => {}, path, '*'); + }; + + if ( + moduleExports && + typeof moduleExports === 'object' && + typeof moduleExports.then === 'function' + ) { + return moduleExports.then( + asyncModuleExports => + createClientReferencesForExports({ + exports: asyncModuleExports, + async: true, + }), + () => {}, + ); + } + + return createClientReferencesForExports({exports: moduleExports}); +}; + // This tests server to server references. There's another case of client to server references. exports.serverExports = function serverExports(moduleExports, blockOnChunk) { const idx = '' + webpackModuleIdx++; diff --git a/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js b/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js index d29516ff946ea..f9d9bf4ea9169 100644 --- a/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js +++ b/packages/react-server-dom-webpack/src/server/ReactFlightServerConfigWebpackBundler.js @@ -71,7 +71,15 @@ export function resolveClientReferenceMetadata( ); } } - if (clientReference.$$async === true) { + if (resolvedModuleData.async === true && clientReference.$$async === true) { + throw new Error( + 'The module "' + + modulePath + + '" is marked as an async ESM module but was loaded as a CJS proxy. ' + + 'This is probably a bug in the React Server Components bundler.', + ); + } + if (resolvedModuleData.async === true || clientReference.$$async === true) { return [resolvedModuleData.id, resolvedModuleData.chunks, name, 1]; } else { return [resolvedModuleData.id, resolvedModuleData.chunks, name]; diff --git a/packages/react-server-dom-webpack/src/shared/ReactFlightImportMetadata.js b/packages/react-server-dom-webpack/src/shared/ReactFlightImportMetadata.js index 08aafaf00c605..29b012f605204 100644 --- a/packages/react-server-dom-webpack/src/shared/ReactFlightImportMetadata.js +++ b/packages/react-server-dom-webpack/src/shared/ReactFlightImportMetadata.js @@ -12,6 +12,7 @@ export type ImportManifestEntry = { // chunks is a double indexed array of chunkId / chunkFilename pairs chunks: Array, name: string, + async?: boolean, }; // This is the parsed shape of the wire format which is why it is From 6774caa37973e3e26d60f100971e5e785fd12235 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 13 Sep 2024 15:55:42 -0700 Subject: [PATCH 142/426] [Flight] properly track pendingChunks when changing environment names (#30958) When the environment name changes for a chunk we issue a new debug chunk which updates the environment name. This chunk was not beign included in the pendingChunks count so the count was off when flushing --- packages/react-server/src/ReactFlightServer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 7ee275e060a82..b40c0628b2c28 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -3813,6 +3813,7 @@ function retryTask(request: Request, task: Task): void { if (__DEV__) { const currentEnv = (0, request.environmentName)(); if (currentEnv !== task.environmentName) { + request.pendingChunks++; // The environment changed since we last emitted any debug information for this // task. We emit an entry that just includes the environment name change. emitDebugChunk(request, task.id, {env: currentEnv}); @@ -3831,6 +3832,7 @@ function retryTask(request: Request, task: Task): void { if (__DEV__) { const currentEnv = (0, request.environmentName)(); if (currentEnv !== task.environmentName) { + request.pendingChunks++; // The environment changed since we last emitted any debug information for this // task. We emit an entry that just includes the environment name change. emitDebugChunk(request, task.id, {env: currentEnv}); From 3d95c43b8967d4dda1ec9a22f0d9ea4999fee8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 13 Sep 2024 21:51:52 -0400 Subject: [PATCH 143/426] [Fiber] Profiler - Use two separate functions instead of branch by flag (#30957) Nit: I don't trust flags in hot code. While it can take somewhat longer to compile two functions and JIT them. After that they don't need to check branches. Also makes it clearer the purpose. --- .../src/ReactFiberWorkLoop.js | 13 +++++----- .../src/ReactProfilerTimer.js | 26 ++++++++++++++----- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 8322fad7cd18b..3c0cafacfe202 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -225,7 +225,8 @@ import { recordCommitTime, resetNestedUpdateFlag, startProfilerTimer, - stopProfilerTimerIfRunningAndRecordDelta, + stopProfilerTimerIfRunningAndRecordDuration, + stopProfilerTimerIfRunningAndRecordIncompleteDuration, syncNestedUpdateFlag, } from './ReactProfilerTimer'; @@ -1844,7 +1845,7 @@ function handleThrow(root: FiberRoot, thrownValue: any): void { // Record the time spent rendering before an error was thrown. This // avoids inaccurate Profiler durations in the case of a // suspended render. - stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true); + stopProfilerTimerIfRunningAndRecordDuration(erroredWork); } if (enableSchedulingProfiler) { @@ -2516,7 +2517,7 @@ function performUnitOfWork(unitOfWork: Fiber): void { } else { next = beginWork(current, unitOfWork, entangledRenderLanes); } - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + stopProfilerTimerIfRunningAndRecordDuration(unitOfWork); } else { if (__DEV__) { next = runWithFiberInDEV( @@ -2660,7 +2661,7 @@ function replayBeginWork(unitOfWork: Fiber): null | Fiber { } } if (isProfilingMode) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + stopProfilerTimerIfRunningAndRecordDuration(unitOfWork); } return next; @@ -2851,7 +2852,7 @@ function completeUnitOfWork(unitOfWork: Fiber): void { next = completeWork(current, completedWork, entangledRenderLanes); } // Update render duration assuming we didn't error. - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); + stopProfilerTimerIfRunningAndRecordIncompleteDuration(completedWork); } if (next !== null) { @@ -2909,7 +2910,7 @@ function unwindUnitOfWork(unitOfWork: Fiber, skipSiblings: boolean): void { if (enableProfilerTimer && (incompleteWork.mode & ProfileMode) !== NoMode) { // Record the render duration for the fiber that errored. - stopProfilerTimerIfRunningAndRecordDelta(incompleteWork, false); + stopProfilerTimerIfRunningAndRecordIncompleteDuration(incompleteWork); // Include the time spent working on failed children before continuing. let actualDuration = incompleteWork.actualDuration; diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index eaa24dc9fdc3b..e0c634b190001 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -29,7 +29,8 @@ export type ProfilerTimer = { recordCommitTime(): void, startProfilerTimer(fiber: Fiber): void, stopProfilerTimerIfRunning(fiber: Fiber): void, - stopProfilerTimerIfRunningAndRecordDelta(fiber: Fiber): void, + stopProfilerTimerIfRunningAndRecordDuration(fiber: Fiber): void, + stopProfilerTimerIfRunningAndRecordIncompleteDuration(fiber: Fiber): void, syncNestedUpdateFlag(): void, ... }; @@ -112,9 +113,21 @@ function stopProfilerTimerIfRunning(fiber: Fiber): void { profilerStartTime = -1; } -function stopProfilerTimerIfRunningAndRecordDelta( +function stopProfilerTimerIfRunningAndRecordDuration(fiber: Fiber): void { + if (!enableProfilerTimer) { + return; + } + + if (profilerStartTime >= 0) { + const elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; + fiber.selfBaseDuration = elapsedTime; + profilerStartTime = -1; + } +} + +function stopProfilerTimerIfRunningAndRecordIncompleteDuration( fiber: Fiber, - overrideBaseTime: boolean, ): void { if (!enableProfilerTimer) { return; @@ -123,9 +136,7 @@ function stopProfilerTimerIfRunningAndRecordDelta( if (profilerStartTime >= 0) { const elapsedTime = now() - profilerStartTime; fiber.actualDuration += elapsedTime; - if (overrideBaseTime) { - fiber.selfBaseDuration = elapsedTime; - } + // We don't update the selfBaseDuration here because we errored. profilerStartTime = -1; } } @@ -233,7 +244,8 @@ export { startPassiveEffectTimer, startProfilerTimer, stopProfilerTimerIfRunning, - stopProfilerTimerIfRunningAndRecordDelta, + stopProfilerTimerIfRunningAndRecordDuration, + stopProfilerTimerIfRunningAndRecordIncompleteDuration, syncNestedUpdateFlag, transferActualDuration, }; From b75cc078c5fda0d57135523a7a2f4e8d1536472f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=A5=E5=B8=8C=E4=B8=8E=E5=AD=90=E6=99=B4?= Date: Sat, 14 Sep 2024 23:18:27 +0800 Subject: [PATCH 144/426] Fix nodeName to UPPERCASE in insertStylesheetIntoRoot (#28255) ## Summary image The condition `node.nodeName === 'link'` is always `false`, because `node.nodeName` is Uppercase in specification. And the condition `node.nodeName === 'LINK'` is unnecessary, because Fizz hoists tags when it's `media` attribute is `"not all"`, whether it is a `link` or a `style` (line 36): https://github.com/facebook/react/blob/18cbcbf783377c5a22277a63ae41af54504502e0/packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetExternalRuntime.js#L30-L44 https://github.com/facebook/react/blob/18cbcbf783377c5a22277a63ae41af54504502e0/packages/react-dom-bindings/src/server/fizz-instruction-set/ReactDOMFizzInstructionSetInlineSource.js#L30-L44 --- packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index b2eec77f6b4cb..0e39f988f813c 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3520,7 +3520,7 @@ function insertStylesheetIntoRoot( for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if ( - node.nodeName === 'link' || + node.nodeName === 'LINK' || // We omit style tags with media="not all" because they are not in the right position // and will be hoisted by the Fizz runtime imminently. node.getAttribute('media') !== 'not all' From fc5ef50da8e975a569622d477f1fed54cb8b193d Mon Sep 17 00:00:00 2001 From: Josh Story Date: Sat, 14 Sep 2024 09:26:01 -0700 Subject: [PATCH 145/426] [Flight] Start initial work immediately (#30961) In a past update we made render and prerender have different work scheduling behavior because these methods are meant to be used in differeent environments with different performance tradeoffs in mind. For instance to prioritize streaming we want to allow as much IO to complete before triggering a round of work because we want to flush as few intermediate UI states. With Prerendering there will never be any intermediate UI states so we can more aggressively render tasks as they complete. One thing we've found is that even during render we should ideally kick off work immediately. This update normalizes the intitial work for render and prerender to start in a microtask. Choosing microtask over sync is somewhat arbitrary but there really isn't a reason to make them different between render/prerender so for now we'll unify them and keep it as a microtask for now. This change also updates pinging behavior. If the request is still in the initial task that spawned it then pings will schedule on the microtask queue. This allows immediately available async APIs to resolve right away. The concern with doing this for normal pings is that it might crowd out IO events but since this is the initial task there would be IO to already be scheduled. --- .../react-server/src/ReactFlightServer.js | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index b40c0628b2c28..f0e632c5499b0 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -352,8 +352,17 @@ type Task = { interface Reference {} +const OPENING = 10; +const OPEN = 11; +const ABORTING = 12; +const CLOSING = 13; +const CLOSED = 14; + +const RENDER = 20; +const PRERENDER = 21; + export type Request = { - status: 10 | 11 | 12 | 13, + status: 10 | 11 | 12 | 13 | 14, type: 20 | 21, flushScheduled: boolean, fatalError: mixed, @@ -426,14 +435,6 @@ function defaultPostponeHandler(reason: string) { // Noop } -const OPEN = 10; -const ABORTING = 11; -const CLOSING = 12; -const CLOSED = 13; - -const RENDER = 20; -const PRERENDER = 21; - function RequestInstance( this: $FlowFixMe, type: 20 | 21, @@ -472,7 +473,7 @@ function RequestInstance( } const hints = createHints(); this.type = type; - this.status = OPEN; + this.status = OPENING; this.flushScheduled = false; this.fatalError = null; this.destination = null; @@ -1794,7 +1795,7 @@ function pingTask(request: Request, task: Task): void { pingedTasks.push(task); if (pingedTasks.length === 1) { request.flushScheduled = request.destination !== null; - if (request.type === PRERENDER) { + if (request.type === PRERENDER || request.status === OPENING) { scheduleMicrotask(() => performWork(request)); } else { scheduleWork(() => performWork(request)); @@ -4062,21 +4063,18 @@ function flushCompletedChunks( export function startWork(request: Request): void { request.flushScheduled = request.destination !== null; - if (request.type === PRERENDER) { - if (supportsRequestStorage) { - scheduleMicrotask(() => { - requestStorage.run(request, performWork, request); - }); - } else { - scheduleMicrotask(() => performWork(request)); - } + if (supportsRequestStorage) { + scheduleMicrotask(() => { + requestStorage.run(request, performWork, request); + }); } else { - if (supportsRequestStorage) { - scheduleWork(() => requestStorage.run(request, performWork, request)); - } else { - scheduleWork(() => performWork(request)); - } + scheduleMicrotask(() => performWork(request)); } + scheduleWork(() => { + if (request.status === OPENING) { + request.status = OPEN; + } + }); } function enqueueFlush(request: Request): void { @@ -4129,7 +4127,8 @@ export function stopFlowing(request: Request): void { export function abort(request: Request, reason: mixed): void { try { - if (request.status === OPEN) { + // We define any status below OPEN as OPEN equivalent + if (request.status <= OPEN) { request.status = ABORTING; } const abortableTasks = request.abortableTasks; From 8cf64620c7dd4ec7e72aa16ee2d5f15eb3420b92 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Mon, 16 Sep 2024 14:47:57 +0100 Subject: [PATCH 146/426] fix[rdt/fiber/renderer.js]: getCurrentFiber can be injected as null (#30968) In production artifacts for `18.x.x` `getCurrentFiber` can actually be injected as `null`. Updated `getComponentStack` and `onErrorOrWarning` implementations to support this. ![Screenshot 2024-09-16 at 10 52 00](https://github.com/user-attachments/assets/a0c773aa-ebbf-4fd5-95c4-cac3cc0c203f) --- packages/react-devtools-shared/src/backend/fiber/renderer.js | 4 ++-- packages/react-devtools-shared/src/backend/types.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 1ac78a49a58b6..2fd768b5d01c3 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -1078,7 +1078,7 @@ export function attach( function getComponentStack( topFrame: Error, ): null | {enableOwnerStacks: boolean, componentStack: string} { - if (getCurrentFiber === undefined) { + if (getCurrentFiber == null) { // Expected this to be part of the renderer. Ignore. return null; } @@ -1130,7 +1130,7 @@ export function attach( type: 'error' | 'warn', args: $ReadOnlyArray, ): void { - if (getCurrentFiber === undefined) { + if (getCurrentFiber == null) { // Expected this to be part of the renderer. Ignore. return; } diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index e3c062fefaaf3..7d816d403af07 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -158,7 +158,7 @@ export type ReactRenderer = { currentDispatcherRef?: LegacyDispatcherRef | CurrentDispatcherRef, // Only injected by React v16.9+ in DEV mode. // Enables DevTools to append owners-only component stack to error messages. - getCurrentFiber?: () => Fiber | null, + getCurrentFiber?: (() => Fiber | null) | null, // Only injected by React Flight Clients in DEV mode. // Enables DevTools to append owners-only component stack to error messages from Server Components. getCurrentComponentInfo?: () => ReactComponentInfo | null, From 0eab377a96099f0121009c8968c49d13d4e00bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 16 Sep 2024 11:09:40 -0400 Subject: [PATCH 147/426] Add enableComponentPerformanceTrack Flag (#30960) This flag will be used to gate a new timeline profiler that's integrate with the Performance Tab and the new performance.measure extensions in Chrome. It replaces the existing DevTools feature so this disables enableSchedulingProfiler when it is enabled since they can interplay in weird ways potentially. This means that experimental React now disable scheduling profiler and enables this new approach. --- .../src/__tests__/TimelineProfiler-test.js | 18 ++++++++++--- .../src/__tests__/preprocessData-test.js | 27 ++++++++++++++----- packages/shared/ReactFeatureFlags.js | 15 ++++++++--- .../forks/ReactFeatureFlags.native-fb.js | 1 + .../forks/ReactFeatureFlags.native-oss.js | 1 + .../forks/ReactFeatureFlags.test-renderer.js | 1 + ...actFeatureFlags.test-renderer.native-fb.js | 1 + .../ReactFeatureFlags.test-renderer.www.js | 1 + .../shared/forks/ReactFeatureFlags.www.js | 2 ++ 9 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js b/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js index ecbe336bdcbe0..b4cc9bbc0bafc 100644 --- a/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js +++ b/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js @@ -18,6 +18,11 @@ import { import {ReactVersion} from '../../../../ReactVersions'; import semver from 'semver'; +let React = require('react'); +let Scheduler; +let store; +let utils; + // TODO: This is how other DevTools tests access the version but we should find // a better solution for this const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion; @@ -26,11 +31,16 @@ const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion; const enableSiblingPrerendering = false && semver.gte(ReactVersionTestingAgainst, '19.0.0'); +// This flag is on experimental which disables timeline profiler. +const enableComponentPerformanceTrack = + React.version.startsWith('19') && React.version.includes('experimental'); + describe('Timeline profiler', () => { - let React; - let Scheduler; - let store; - let utils; + if (enableComponentPerformanceTrack) { + test('no tests', () => {}); + // Ignore all tests. + return; + } beforeEach(() => { utils = require('./utils'); diff --git a/packages/react-devtools-shared/src/__tests__/preprocessData-test.js b/packages/react-devtools-shared/src/__tests__/preprocessData-test.js index 06595b67ca1a0..7a77ab20eb9cf 100644 --- a/packages/react-devtools-shared/src/__tests__/preprocessData-test.js +++ b/packages/react-devtools-shared/src/__tests__/preprocessData-test.js @@ -16,16 +16,29 @@ import {ReactVersion} from '../../../../ReactVersions'; const ReactVersionTestingAgainst = process.env.REACT_VERSION || ReactVersion; +let React = require('react'); +let ReactDOM; +let ReactDOMClient; +let Scheduler; +let utils; +let assertLog; +let waitFor; + +// This flag is on experimental which disables timeline profiler. +const enableComponentPerformanceTrack = + React.version.startsWith('19') && React.version.includes('experimental'); + describe('Timeline profiler', () => { - let React; - let ReactDOM; - let ReactDOMClient; - let Scheduler; - let utils; - let assertLog; - let waitFor; + if (enableComponentPerformanceTrack) { + test('no tests', () => {}); + // Ignore all tests. + return; + } describe('User Timing API', () => { + if (enableComponentPerformanceTrack) { + return; + } let currentlyNotClearedMarks; let registeredMarks; let featureDetectionMarkName = null; diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 3331deded9af9..9935784b533d2 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -260,10 +260,6 @@ export const disableTextareaChildren = false; // Debugging and DevTools // ----------------------------------------------------------------------------- -// Adds user timing marks for e.g. state updates, suspense, and work loop stuff, -// for an experimental timeline tool. -export const enableSchedulingProfiler = __PROFILE__; - // Helps identify side effects in render-phase lifecycle hooks and setState // reducers by double invoking them in StrictLegacyMode. export const debugRenderPhaseSideEffectsForStrictMode = __DEV__; @@ -271,6 +267,17 @@ export const debugRenderPhaseSideEffectsForStrictMode = __DEV__; // Gather advanced timing metrics for Profiler subtrees. export const enableProfilerTimer = __PROFILE__; +// Adds performance.measure() marks using Chrome extensions to allow formatted +// Component rendering tracks to show up in the Performance tab. +// This flag will be used for both Server Component and Client Component tracks. +// All calls should also be gated on enableProfilerTimer. +export const enableComponentPerformanceTrack = __EXPERIMENTAL__; + +// Adds user timing marks for e.g. state updates, suspense, and work loop stuff, +// for an experimental timeline tool. +export const enableSchedulingProfiler: boolean = + !enableComponentPerformanceTrack && __PROFILE__; + // Record durations for commit and passive effects phases. export const enableProfilerCommitHooks = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index a6001a9559609..83df5ed548da8 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -77,6 +77,7 @@ export const enableRefAsProp = true; export const enableRenderableContext = true; export const enableRetryLaneExpiration = false; export const enableSchedulingProfiler = __PROFILE__; +export const enableComponentPerformanceTrack = false; export const enableScopeAPI = false; export const enableServerComponentLogs = true; export const enableSuspenseAvoidThisFallback = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 723cc06c33a27..55ab25639fea0 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -67,6 +67,7 @@ export const enableRefAsProp = true; export const enableRenderableContext = true; export const enableRetryLaneExpiration = false; export const enableSchedulingProfiler = __PROFILE__; +export const enableComponentPerformanceTrack = false; export const enableScopeAPI = false; export const enableServerComponentLogs = true; export const enableShallowPropDiffing = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 3581d31831784..d12029a672f7c 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -17,6 +17,7 @@ export const enableSchedulingProfiler = false; export const enableProfilerTimer = __PROFILE__; export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; +export const enableComponentPerformanceTrack = false; export const enableUpdaterTracking = false; export const enableCache = true; export const enableLegacyCache = __EXPERIMENTAL__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index edf67adf18bc3..31b3a118eae5a 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -61,6 +61,7 @@ export const enableRefAsProp = true; export const enableRenderableContext = true; export const enableRetryLaneExpiration = false; export const enableSchedulingProfiler = __PROFILE__; +export const enableComponentPerformanceTrack = false; export const enableScopeAPI = false; export const enableServerComponentLogs = true; export const enableShallowPropDiffing = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index e64904005e143..59850bac75099 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -17,6 +17,7 @@ export const enableSchedulingProfiler = false; export const enableProfilerTimer = __PROFILE__; export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; +export const enableComponentPerformanceTrack = false; export const enableUpdaterTracking = false; export const enableCache = true; export const enableLegacyCache = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index e6025242d4a78..0caf25c155625 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -62,6 +62,8 @@ export const disableInputAttributeSyncing = false; export const enableLegacyFBSupport = true; export const enableLazyContextPropagation = true; +export const enableComponentPerformanceTrack = false; + // Logs additional User Timing API marks for use with an experimental profiling tool. export const enableSchedulingProfiler: boolean = __PROFILE__ && dynamicFeatureFlags.enableSchedulingProfiler; From ee1a403a3019dd8bffb12174d269d8c85bfab8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 16 Sep 2024 11:10:05 -0400 Subject: [PATCH 148/426] [Fiber] Move Profiler onPostCommit processing of passive effect durations to plain passive effect (#30966) We used to queue a separate third passive phase to invoke onPostCommit but this is unnecessary. We can just treat it as a plain passive effect. This means it is interleaved with other passive effects but we only need to know the duration of the things below us which is already done at this point. I also extracted the user space call to onPostCommit into ReactCommitEffects. Same as onCommit. It's now covered by runWithFiberInDEV and catches. --- .../src/ReactFiberBeginWork.js | 8 ++ .../src/ReactFiberCommitEffects.js | 53 +++++++- .../src/ReactFiberCommitWork.js | 116 +++++++----------- .../src/ReactFiberWorkLoop.js | 25 ---- 4 files changed, 106 insertions(+), 96 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index c71b7044756ba..398dd8372597a 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1026,6 +1026,10 @@ function updateProfiler( workInProgress.flags |= Update; if (enableProfilerCommitHooks) { + // Schedule a passive effect for this Profiler to call onPostCommit hooks. + // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, + // because the effect is also where times bubble to parent Profilers. + workInProgress.flags |= Passive; // Reset effect durations for the next eventual effect phase. // These are reset during render to allow the DevTools commit hook a chance to read them, const stateNode = workInProgress.stateNode; @@ -3700,6 +3704,10 @@ function attemptEarlyBailoutIfNoScheduledUpdate( } if (enableProfilerCommitHooks) { + // Schedule a passive effect for this Profiler to call onPostCommit hooks. + // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, + // because the effect is also where times bubble to parent Profilers. + workInProgress.flags |= Passive; // Reset effect durations for the next eventual effect phase. // These are reset during render to allow the DevTools commit hook a chance to read them, const stateNode = workInProgress.stateNode; diff --git a/packages/react-reconciler/src/ReactFiberCommitEffects.js b/packages/react-reconciler/src/ReactFiberCommitEffects.js index 1d9d5c65b8aa4..af5762df2110a 100644 --- a/packages/react-reconciler/src/ReactFiberCommitEffects.js +++ b/packages/react-reconciler/src/ReactFiberCommitEffects.js @@ -881,7 +881,7 @@ function commitProfiler( commitTime: number, effectDuration: number, ) { - const {onCommit, onRender} = finishedWork.memoizedProps; + const {id, onCommit, onRender} = finishedWork.memoizedProps; let phase = current === null ? 'mount' : 'update'; if (enableProfilerNestedUpdatePhase) { @@ -892,7 +892,7 @@ function commitProfiler( if (typeof onRender === 'function') { onRender( - finishedWork.memoizedProps.id, + id, phase, finishedWork.actualDuration, finishedWork.treeBaseDuration, @@ -938,3 +938,52 @@ export function commitProfilerUpdate( } } } + +function commitProfilerPostCommitImpl( + finishedWork: Fiber, + current: Fiber | null, + commitTime: number, + passiveEffectDuration: number, +): void { + const {id, onPostCommit} = finishedWork.memoizedProps; + + let phase = current === null ? 'mount' : 'update'; + if (enableProfilerNestedUpdatePhase) { + if (isCurrentUpdateNested()) { + phase = 'nested-update'; + } + } + + if (typeof onPostCommit === 'function') { + onPostCommit(id, phase, passiveEffectDuration, commitTime); + } +} + +export function commitProfilerPostCommit( + finishedWork: Fiber, + current: Fiber | null, + commitTime: number, + passiveEffectDuration: number, +) { + try { + if (__DEV__) { + runWithFiberInDEV( + finishedWork, + commitProfilerPostCommitImpl, + finishedWork, + current, + commitTime, + passiveEffectDuration, + ); + } else { + commitProfilerPostCommitImpl( + finishedWork, + current, + commitTime, + passiveEffectDuration, + ); + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } +} diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 17c104ff0fff9..bb37628c2d7a7 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -44,7 +44,6 @@ import { enablePersistedModeClonedFlag, enableProfilerTimer, enableProfilerCommitHooks, - enableProfilerNestedUpdatePhase, enableSchedulingProfiler, enableSuspenseCallback, enableScopeAPI, @@ -100,7 +99,6 @@ import { Cloned, } from './ReactFiberFlags'; import { - isCurrentUpdateNested, getCommitTime, recordLayoutEffectDuration, startLayoutEffectTimer, @@ -137,7 +135,6 @@ import { captureCommitPhaseError, resolveRetryWakeable, markCommitTimeOfFallback, - enqueuePendingPassiveProfilerEffect, restorePendingUpdaters, addTransitionStartCallbackToPendingTransition, addTransitionProgressCallbackToPendingTransition, @@ -193,6 +190,7 @@ import { safelyDetachRef, safelyCallDestroy, commitProfilerUpdate, + commitProfilerPostCommit, commitRootCallbacks, } from './ReactFiberCommitEffects'; import { @@ -394,62 +392,6 @@ function commitBeforeMutationEffectsDeletion(deletion: Fiber) { } } -export function commitPassiveEffectDurations( - finishedRoot: FiberRoot, - finishedWork: Fiber, -): void { - if ( - enableProfilerTimer && - enableProfilerCommitHooks && - getExecutionContext() & CommitContext - ) { - // Only Profilers with work in their subtree will have an Update effect scheduled. - if ((finishedWork.flags & Update) !== NoFlags) { - switch (finishedWork.tag) { - case Profiler: { - const {passiveEffectDuration} = finishedWork.stateNode; - const {id, onPostCommit} = finishedWork.memoizedProps; - - // This value will still reflect the previous commit phase. - // It does not get reset until the start of the next commit phase. - const commitTime = getCommitTime(); - - let phase = finishedWork.alternate === null ? 'mount' : 'update'; - if (enableProfilerNestedUpdatePhase) { - if (isCurrentUpdateNested()) { - phase = 'nested-update'; - } - } - - if (typeof onPostCommit === 'function') { - onPostCommit(id, phase, passiveEffectDuration, commitTime); - } - - // Bubble times to the next nearest ancestor Profiler. - // After we process that Profiler, we'll bubble further up. - let parentFiber = finishedWork.return; - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - const root = parentFiber.stateNode; - root.passiveEffectDuration += passiveEffectDuration; - break outer; - case Profiler: - const parentStateNode = parentFiber.stateNode; - parentStateNode.passiveEffectDuration += passiveEffectDuration; - break outer; - } - parentFiber = parentFiber.return; - } - break; - } - default: - break; - } - } - } -} - function commitLayoutEffectOnFiber( finishedRoot: FiberRoot, current: Fiber | null, @@ -557,11 +499,6 @@ function commitLayoutEffectOnFiber( effectDuration, ); - // Schedule a passive effect for this Profiler to call onPostCommit hooks. - // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, - // because the effect is also where times bubble to parent Profilers. - enqueuePendingPassiveProfilerEffect(finishedWork); - // Propagate layout effect durations to the next nearest Profiler ancestor. // Do not reset these values until the next render so DevTools has a chance to read them first. let parentFiber = finishedWork.return; @@ -2475,11 +2412,6 @@ export function reappearLayoutEffects( effectDuration, ); - // Schedule a passive effect for this Profiler to call onPostCommit hooks. - // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, - // because the effect is also where times bubble to parent Profilers. - enqueuePendingPassiveProfilerEffect(finishedWork); - // Propagate layout effect durations to the next nearest Profiler ancestor. // Do not reset these values until the next render so DevTools has a chance to read them first. let parentFiber = finishedWork.return; @@ -2824,6 +2756,52 @@ function commitPassiveMountOnFiber( } break; } + case Profiler: { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + ); + + // Only Profilers with work in their subtree will have a Passive effect scheduled. + if (flags & Passive) { + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + getExecutionContext() & CommitContext + ) { + const {passiveEffectDuration} = finishedWork.stateNode; + + commitProfilerPostCommit( + finishedWork, + finishedWork.alternate, + // This value will still reflect the previous commit phase. + // It does not get reset until the start of the next commit phase. + getCommitTime(), + passiveEffectDuration, + ); + + // Bubble times to the next nearest ancestor Profiler. + // After we process that Profiler, we'll bubble further up. + let parentFiber = finishedWork.return; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + const root = parentFiber.stateNode; + root.passiveEffectDuration += passiveEffectDuration; + break outer; + case Profiler: + const parentStateNode = parentFiber.stateNode; + parentStateNode.passiveEffectDuration += passiveEffectDuration; + break outer; + } + parentFiber = parentFiber.return; + } + } + } + break; + } case LegacyHiddenComponent: { if (enableLegacyHidden) { recursivelyTraversePassiveMountEffects( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 3c0cafacfe202..c3f413d0ed0b9 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -189,7 +189,6 @@ import { commitBeforeMutationEffects, commitLayoutEffects, commitMutationEffects, - commitPassiveEffectDurations, commitPassiveMountEffects, commitPassiveUnmountEffects, disappearLayoutEffects, @@ -580,7 +579,6 @@ let legacyErrorBoundariesThatAlreadyFailed: Set | null = null; let rootDoesHavePassiveEffects: boolean = false; let rootWithPendingPassiveEffects: FiberRoot | null = null; let pendingPassiveEffectsLanes: Lanes = NoLanes; -let pendingPassiveProfilerEffects: Array = []; let pendingPassiveEffectsRemainingLanes: Lanes = NoLanes; let pendingPassiveTransitions: Array | null = null; @@ -3475,19 +3473,6 @@ export function flushPassiveEffects(): boolean { return false; } -export function enqueuePendingPassiveProfilerEffect(fiber: Fiber): void { - if (enableProfilerTimer && enableProfilerCommitHooks) { - pendingPassiveProfilerEffects.push(fiber); - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalSchedulerPriority, () => { - flushPassiveEffects(); - return null; - }); - } - } -} - function flushPassiveEffectsImpl() { if (rootWithPendingPassiveEffects === null) { return false; @@ -3528,16 +3513,6 @@ function flushPassiveEffectsImpl() { commitPassiveUnmountEffects(root.current); commitPassiveMountEffects(root, root.current, lanes, transitions); - // TODO: Move to commitPassiveMountEffects - if (enableProfilerTimer && enableProfilerCommitHooks) { - const profilerEffects = pendingPassiveProfilerEffects; - pendingPassiveProfilerEffects = []; - for (let i = 0; i < profilerEffects.length; i++) { - const fiber = ((profilerEffects[i]: any): Fiber); - commitPassiveEffectDurations(root, fiber); - } - } - if (__DEV__) { if (enableDebugTracing) { logPassiveEffectsStopped(); From f2df5694f2be141954f22618fd3ad035203241a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 16 Sep 2024 11:45:50 -0400 Subject: [PATCH 149/426] [Fiber] Log Component Renders to Custom Performance Track (#30967) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacked on #30960 and #30966. Behind the enableComponentPerformanceTrack flag. This is the first step of performance logging. This logs the start and end time of a component render in the passive effect phase. We use the data we're already tracking on components when the Profiler component or DevTools is active in the Profiling or Dev builds. By backdating this after committing we avoid adding more overhead in the hot path. By only logging things that actually committed, we avoid the costly unwinding of an interrupted render which was hard to maintain in earlier versions. We already have the start time but we don't have the end time. That's because `actualStartTime + actualDuration` isn't enough since `actualDuration` counts the actual CPU time excluding yields and suspending in the render. Instead, we infer the end time to be the start time of the next sibling or the complete time of the whole root if there are no more siblings. We need to pass this down the passive effect tree. This will mean that any overhead and yields are attributed to this component's span. In a follow up, we'll need to start logging these yields to make it clear that this is not part of the component's self-time. In follow ups, I'll do the same for commit phases. We'll also need to log more information about the phases in the top track. We'll also need to filter out more components from the trees that we don't need to highlight like the internal Offscreen components. It also needs polish on colors etc. Currently, I place the components into separate tracks depending on which lane currently committed. That way you can see what was blocking Transitions or Suspense etc. One problem that I've hit with the new performance.measure extensions is that these tracks show up in the order they're used which is not the order of priority that we use. Even when you add fake markers they have to actually be within the performance run since otherwise the calls are noops so it's not enough to do that once. However, I think this visualization is actually not good because these trees end up so large that you can't see any other lanes once you expand one. Therefore, I think in a follow up I'll actually instead switch to a model where Components is a single track regardless of lane since we don't currently have overlap anyway. Then the description about what is actually rendering can be separate lanes. Screenshot 2024-09-15 at 10 55 55 PM Screenshot 2024-09-15 at 10 56 27 PM --- .../src/ReactFiberCommitWork.js | 74 +++++++++++++++-- .../react-reconciler/src/ReactFiberLane.js | 32 ++++++++ .../src/ReactFiberPerformanceTrack.js | 61 ++++++++++++++ .../src/ReactFiberWorkLoop.js | 60 ++++++++------ .../src/ReactProfilerTimer.js | 16 +++- .../src/__tests__/ReactSuspenseList-test.js | 10 +++ .../__tests__/ReactProfiler-test.internal.js | 81 +++++++++++++++---- 7 files changed, 285 insertions(+), 49 deletions(-) create mode 100644 packages/react-reconciler/src/ReactFiberPerformanceTrack.js diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index bb37628c2d7a7..bba93bbc0da2e 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -53,6 +53,7 @@ import { enableUseEffectEventHook, enableLegacyHidden, disableLegacyMode, + enableComponentPerformanceTrack, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -102,7 +103,9 @@ import { getCommitTime, recordLayoutEffectDuration, startLayoutEffectTimer, + getCompleteTime, } from './ReactProfilerTimer'; +import {logComponentRender} from './ReactFiberPerformanceTrack'; import {ConcurrentMode, NoMode, ProfileMode} from './ReactTypeOfMode'; import {deferHiddenCallbacks} from './ReactFiberClassUpdateQueue'; import { @@ -2648,6 +2651,9 @@ export function commitPassiveMountEffects( finishedWork, committedLanes, committedTransitions, + enableProfilerTimer && enableComponentPerformanceTrack + ? getCompleteTime() + : 0, ); } @@ -2656,17 +2662,41 @@ function recursivelyTraversePassiveMountEffects( parentFiber: Fiber, committedLanes: Lanes, committedTransitions: Array | null, + endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ) { - if (parentFiber.subtreeFlags & PassiveMask) { + if ( + parentFiber.subtreeFlags & PassiveMask || + // If this subtree rendered with profiling this commit, we need to visit it to log it. + (enableProfilerTimer && + enableComponentPerformanceTrack && + parentFiber.actualDuration !== 0 && + (parentFiber.alternate === null || + parentFiber.alternate.child !== parentFiber.child)) + ) { let child = parentFiber.child; while (child !== null) { - commitPassiveMountOnFiber( - root, - child, - committedLanes, - committedTransitions, - ); - child = child.sibling; + if (enableProfilerTimer && enableComponentPerformanceTrack) { + const nextSibling = child.sibling; + commitPassiveMountOnFiber( + root, + child, + committedLanes, + committedTransitions, + nextSibling !== null + ? ((nextSibling.actualStartTime: any): number) + : endTime, + ); + child = nextSibling; + } else { + commitPassiveMountOnFiber( + root, + child, + committedLanes, + committedTransitions, + 0, + ); + child = child.sibling; + } } } } @@ -2676,7 +2706,25 @@ function commitPassiveMountOnFiber( finishedWork: Fiber, committedLanes: Lanes, committedTransitions: Array | null, + endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ): void { + // If this component rendered in Profiling mode (DEV or in Profiler component) then log its + // render time. We do this after the fact in the passive effect to avoid the overhead of this + // getting in the way of the render characteristics and avoid the overhead of unwinding + // uncommitted renders. + if ( + enableProfilerTimer && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + ((finishedWork.actualStartTime: any): number) > 0 + ) { + logComponentRender( + finishedWork, + ((finishedWork.actualStartTime: any): number), + endTime, + ); + } + // When updating this function, also update reconnectPassiveEffects, which does // most of the same things when an offscreen tree goes from hidden -> visible, // or when toggling effects inside a hidden tree. @@ -2690,6 +2738,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { commitHookPassiveMountEffects( @@ -2705,6 +2754,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { if (enableCache) { @@ -2762,6 +2812,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); // Only Profilers with work in their subtree will have a Passive effect scheduled. @@ -2809,6 +2860,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { @@ -2834,6 +2886,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); } else { if (disableLegacyMode || finishedWork.mode & ConcurrentMode) { @@ -2858,6 +2911,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); } } @@ -2870,6 +2924,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); } else { // The effects are currently disconnected. Reconnect them, while also @@ -2901,6 +2956,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { // TODO: Pass `current` as argument to this function @@ -2916,6 +2972,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); if (flags & Passive) { commitTracingMarkerPassiveMountEffect(finishedWork); @@ -2930,6 +2987,7 @@ function commitPassiveMountOnFiber( finishedWork, committedLanes, committedTransitions, + endTime, ); break; } diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index 4338d3af58546..f72174e208555 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -1143,3 +1143,35 @@ export function clearTransitionsForLanes(root: FiberRoot, lanes: Lane | Lanes) { lanes &= ~lane; } } + +// Used to name the Performance Track +export function getGroupNameOfHighestPriorityLane(lanes: Lanes): string { + if ( + lanes & + (SyncHydrationLane | + SyncLane | + InputContinuousHydrationLane | + InputContinuousLane | + DefaultHydrationLane | + DefaultLane) + ) { + return 'Blocking'; + } + if (lanes & (TransitionHydrationLane | TransitionLanes)) { + return 'Transition'; + } + if (lanes & RetryLanes) { + return 'Suspense'; + } + if ( + lanes & + (SelectiveHydrationLane | + IdleHydrationLane | + IdleLane | + OffscreenLane | + DeferredLane) + ) { + return 'Idle'; + } + return 'Other'; +} diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js new file mode 100644 index 0000000000000..2058a04e47454 --- /dev/null +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -0,0 +1,61 @@ +/** + * 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 type {Fiber} from './ReactInternalTypes'; + +import getComponentNameFromFiber from './getComponentNameFromFiber'; + +import {getGroupNameOfHighestPriorityLane} from './ReactFiberLane'; + +import {enableProfilerTimer} from 'shared/ReactFeatureFlags'; + +const supportsUserTiming = + enableProfilerTimer && + typeof performance !== 'undefined' && + // $FlowFixMe[method-unbinding] + typeof performance.measure === 'function'; + +const TRACK_GROUP = 'Components ⚛'; + +// Reused to avoid thrashing the GC. +const reusableComponentDevToolDetails = { + dataType: 'track-entry', + color: 'primary', + track: 'Blocking', // Lane + trackGroup: TRACK_GROUP, +}; +const reusableComponentOptions = { + start: -0, + end: -0, + detail: { + devtools: reusableComponentDevToolDetails, + }, +}; + +export function setCurrentTrackFromLanes(lanes: number): void { + reusableComponentDevToolDetails.track = + getGroupNameOfHighestPriorityLane(lanes); +} + +export function logComponentRender( + fiber: Fiber, + startTime: number, + endTime: number, +): void { + const name = getComponentNameFromFiber(fiber); + if (name === null) { + // Skip + return; + } + if (supportsUserTiming) { + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure(name, reusableComponentOptions); + } +} diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index c3f413d0ed0b9..dba089e81f3e0 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -44,6 +44,7 @@ import { disableDefaultPropsExceptForClasses, disableStringRefs, enableSiblingPrerendering, + enableComponentPerformanceTrack, } from 'shared/ReactFeatureFlags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import is from 'shared/objectIs'; @@ -221,6 +222,7 @@ import { import { markNestedUpdateScheduled, + recordCompleteTime, recordCommitTime, resetNestedUpdateFlag, startProfilerTimer, @@ -228,6 +230,7 @@ import { stopProfilerTimerIfRunningAndRecordIncompleteDuration, syncNestedUpdateFlag, } from './ReactProfilerTimer'; +import {setCurrentTrackFromLanes} from './ReactFiberPerformanceTrack'; // DEV stuff import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber'; @@ -1098,6 +1101,12 @@ function finishConcurrentRender( finishedWork: Fiber, lanes: Lanes, ) { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // Track when we finished the last unit of work, before we actually commit it. + // The commit can be suspended/blocked until we commit it. + recordCompleteTime(); + } + // TODO: The fact that most of these branches are identical suggests that some // of the exit statuses are not best modeled as exit statuses and should be // tracked orthogonally. @@ -1479,6 +1488,10 @@ export function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes): null { return null; } + if (enableProfilerTimer && enableComponentPerformanceTrack) { + recordCompleteTime(); + } + // We now have a consistent tree. Because this is a sync render, we // will commit it even if something suspended. const finishedWork: Fiber = (root.current.alternate: any); @@ -2824,35 +2837,22 @@ function completeUnitOfWork(unitOfWork: Fiber): void { const returnFiber = completedWork.return; let next; - if (!enableProfilerTimer || (completedWork.mode & ProfileMode) === NoMode) { - if (__DEV__) { - next = runWithFiberInDEV( - completedWork, - completeWork, - current, - completedWork, - entangledRenderLanes, - ); - } else { - next = completeWork(current, completedWork, entangledRenderLanes); - } + startProfilerTimer(completedWork); + if (__DEV__) { + next = runWithFiberInDEV( + completedWork, + completeWork, + current, + completedWork, + entangledRenderLanes, + ); } else { - startProfilerTimer(completedWork); - if (__DEV__) { - next = runWithFiberInDEV( - completedWork, - completeWork, - current, - completedWork, - entangledRenderLanes, - ); - } else { - next = completeWork(current, completedWork, entangledRenderLanes); - } + next = completeWork(current, completedWork, entangledRenderLanes); + } + if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) { // Update render duration assuming we didn't error. stopProfilerTimerIfRunningAndRecordIncompleteDuration(completedWork); } - if (next !== null) { // Completing this fiber spawned new work. Work on that next. workInProgress = next; @@ -3104,6 +3104,10 @@ function commitRootImpl( // TODO: Delete all other places that schedule the passive effect callback // They're redundant. if ( + // If this subtree rendered with profiling this commit, we need to visit it to log it. + (enableProfilerTimer && + enableComponentPerformanceTrack && + finishedWork.actualDuration !== 0) || (finishedWork.subtreeFlags & PassiveMask) !== NoFlags || (finishedWork.flags & PassiveMask) !== NoFlags ) { @@ -3494,6 +3498,12 @@ function flushPassiveEffectsImpl() { throw new Error('Cannot flush passive effects while already rendering.'); } + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // We're about to log a lot of profiling for this commit. + // We set this once so we don't have to recompute it for every log. + setCurrentTrackFromLanes(lanes); + } + if (__DEV__) { isFlushingPassiveEffects = true; didScheduleUpdateDuringPassiveEffects = false; diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index e0c634b190001..bad2f60490d54 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -35,6 +35,7 @@ export type ProfilerTimer = { ... }; +let completeTime: number = 0; let commitTime: number = 0; let layoutEffectStartTime: number = -1; let profilerStartTime: number = -1; @@ -83,6 +84,17 @@ function syncNestedUpdateFlag(): void { } } +function getCompleteTime(): number { + return completeTime; +} + +function recordCompleteTime(): void { + if (!enableProfilerTimer) { + return; + } + completeTime = now(); +} + function getCommitTime(): number { return commitTime; } @@ -233,10 +245,12 @@ function transferActualDuration(fiber: Fiber): void { } export { + getCompleteTime, + recordCompleteTime, getCommitTime, + recordCommitTime, isCurrentUpdateNested, markNestedUpdateScheduled, - recordCommitTime, recordLayoutEffectDuration, recordPassiveEffectDuration, resetNestedUpdateFlag, diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js index b4a7bcc186b6d..63c398a657b09 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js @@ -1,3 +1,13 @@ +/** + * 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. + * + * @emails react-core + * @jest-environment node + */ + let React; let ReactNoop; let Scheduler; diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index c4d72ffee7241..a19e9b1c6d161 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -164,22 +164,73 @@ describe(`onRender`, () => { // TODO: unstable_now is called by more places than just the profiler. // Rewrite this test so it's less fragile. if (gate(flags => flags.enableDeferRootSchedulingToMicrotask)) { - assertLog([ - 'read current time', - 'read current time', - 'read current time', - 'read current time', - ]); + if (gate(flags => flags.enableComponentPerformanceTrack)) { + assertLog([ + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + ]); + } else { + assertLog([ + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + ]); + } } else { - assertLog([ - 'read current time', - 'read current time', - 'read current time', - 'read current time', - 'read current time', - 'read current time', - 'read current time', - ]); + if (gate(flags => flags.enableComponentPerformanceTrack)) { + assertLog([ + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + ]); + } else { + assertLog([ + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + 'read current time', + ]); + } } }); From 9f4e4611ead28d34f7f598c9bd12424cf68f5781 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Mon, 16 Sep 2024 17:43:40 +0100 Subject: [PATCH 150/426] fix: add Error prefix to Error objects names (#30969) This fixes printing Error objects in Chrome DevTools. I've observed that Chrome DevTools is not source mapping and linkifying URLs, when was running this on larger apps. Chrome DevTools talks to V8 via Chrome DevTools protocol, every object has a corresponding [`RemoteObject`](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject). When Chrome DevTools sees that Error object is printed in the console, it will try to prettify it. `description` field of the corresponding `RemoteObject` for the `Error` JavaScript object is a combination of `Error` `name`, `message`, `stack` fields. This is not just a raw `stack` field, so our prefix for this field just doesn't work. [V8 is actually filtering out first line of the `stack` field, it only keeps the stack frames as a string, and then this gets prefixed by `name` and `message` fields, if they are available](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/inspector/value-mirror.cc;l=252-311;drc=bdc48d1b1312cc40c00282efb1c9c5f41dcdca9a?fbclid=IwZXh0bgNhZW0CMTEAAR1tMm5YC4jqowObad1qXFT98X4RO76CMkCGNSxZ8rVsg6k2RrdvkVFL0i4_aem_e2fRrqotKdkYIeWlJnk0RA). As an illustration, this: ``` const fakeError = new Error(''); fakeError.name = 'Stack'; fakeError.stack = 'Error Stack:' + stack; ``` will be formatted by `V8` as this `RemoteObject`: ``` { ... description: 'Stack: ...', ... } ``` Notice that there is no `Error` prefix, that was previously added. Because of this, [Chrome DevTools won't even try to symbolicate the stack](https://github.com/ChromeDevTools/devtools-frontend/blob/ee4729d2ccdf5c6715ee40e6697f5464829e3f9a/front_end/panels/console/ErrorStackParser.ts#L33-L35), because it doesn't have such prefix. --- .../react-devtools-shared/src/backend/console.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index d4e9651fa7503..61d2e490eb966 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -229,9 +229,19 @@ export function patch({ // In Chromium, only the stack property is printed but in Firefox the : // gets printed so to make the colon make sense, we name it so we print Stack: // and similarly Safari leave an expandable slot. - fakeError.name = enableOwnerStacks - ? 'Stack' - : 'Component Stack'; // This gets printed + if (__IS_CHROME__ || __IS_EDGE__) { + // Before sending the stack to Chrome DevTools for formatting, + // V8 will reconstruct this according to the template : + // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/inspector/value-mirror.cc;l=252-311;drc=bdc48d1b1312cc40c00282efb1c9c5f41dcdca9a + // It has to start with ^[\w.]*Error\b to trigger stack formatting. + fakeError.name = enableOwnerStacks + ? 'Error Stack' + : 'Error Component Stack'; // This gets printed + } else { + fakeError.name = enableOwnerStacks + ? 'Stack' + : 'Component Stack'; // This gets printed + } // In Chromium, the stack property needs to start with ^[\w.]*Error\b to trigger stack // formatting. Otherwise it is left alone. So we prefix it. Otherwise we just override it // to our own stack. From 26855e4680dedb21f2c73a069ed691822a242db1 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Mon, 16 Sep 2024 17:51:00 +0100 Subject: [PATCH 151/426] [react-native] Fix misleading crash when view config is not found (#30970) ## Summary When a view config can not be found, it currently errors with `TypeError: Cannot read property 'bubblingEventTypes' of null`. Instead invariant at the correct location and prevent further processing of the null viewConfig to improve the error logged. ## How did you test this change? Build and run RN playground app referencing an invalid native view through `requireNativeComponent`. --- .../shims/react-native/ReactNativeViewConfigRegistry.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js b/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js index 98e03187c74a5..5f53e7634afde 100644 --- a/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js +++ b/scripts/rollup/shims/react-native/ReactNativeViewConfigRegistry.js @@ -93,8 +93,8 @@ export function register(name: string, callback: () => ViewConfig): string { * This configuration will be lazy-loaded from UIManager. */ export function get(name: string): ViewConfig { - let viewConfig; - if (!viewConfigs.has(name)) { + let viewConfig = viewConfigs.get(name); + if (viewConfig == null) { const callback = viewConfigCallbacks.get(name); if (typeof callback !== 'function') { invariant( @@ -109,15 +109,14 @@ export function get(name: string): ViewConfig { ); } viewConfig = callback(); + invariant(viewConfig, 'View config not found for component `%s`', name); + processEventTypes(viewConfig); viewConfigs.set(name, viewConfig); // Clear the callback after the config is set so that // we don't mask any errors during registration. viewConfigCallbacks.set(name, null); - } else { - viewConfig = viewConfigs.get(name); } - invariant(viewConfig, 'View config not found for name %s', name); return viewConfig; } From c8a7cab13f9d496d4b178ba5e95b030ca854aa20 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Mon, 16 Sep 2024 10:53:29 -0700 Subject: [PATCH 152/426] [compiler] Fix issue where second argument of all functions was considered to be a ref ghstack-source-id: 1817f3b816ab5ec013a3b1a6c8a8373a30e0b3a0 Pull Request resolved: https://github.com/facebook/react/pull/30912 --- .../babel-plugin-react-compiler/src/TypeInference/InferTypes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index b460124ec71f3..25bc87838ae83 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -107,7 +107,7 @@ function equation(left: Type, right: Type): TypeEquation { function* generate( func: HIRFunction, ): Generator { - if (func.env.fnType === 'Component') { + if (func.fnType === 'Component') { const [props, ref] = func.params; if (props && props.kind === 'Identifier') { yield equation(props.identifier.type, { From 1e68a0a3aed9975d2e302ccf1dff0861bf2be706 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Mon, 16 Sep 2024 10:53:32 -0700 Subject: [PATCH 153/426] [compiler] Improve handling of refs Summary: This change expands our handling of refs to build an understanding of nested refs within objects and functions that may return refs. It builds a special-purpose type system within the ref analysis that gives a very lightweight structural type to objects and array expressions (merging the types of all their members), and then propagating those types throughout the analysis (e.g., if `ref` has type `Ref`, then `{ x: ref }` and `[ref]` have type `Structural(value=Ref)` and `{x: ref}.anything` and `[ref][anything]` have type `Ref`). This allows us to support structures that contain refs, and functions that operate over them, being created and passed around during rendering without at runtime accessing a ref value. The analysis here uses a fixpoint to allow types to be fully propagated through the system, and we defend against diverging by widening the type of a variable if it could grow infinitely: so, in something like ``` let x = ref; while (condition) { x = [x] } ``` we end up giving `x` the type `Structural(value=Ref)`. ghstack-source-id: afb0b0cb014ffcf21ef4d0ede6511330fd975ec3 Pull Request resolved: https://github.com/facebook/react/pull/30902 --- .../Validation/ValidateNoRefAccesInRender.ts | 647 +++++++++++------- .../capture-ref-for-later-mutation.expect.md | 69 ++ ...tsx => capture-ref-for-later-mutation.tsx} | 0 ... error.capture-ref-for-mutation.expect.md} | 10 +- .../error.capture-ref-for-mutation.tsx | 23 + .../capture-ref-for-later-mutation.expect.md | 70 ++ .../capture-ref-for-later-mutation.tsx | 24 + 7 files changed, 579 insertions(+), 264 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.capture-ref-for-later-mutation.tsx => capture-ref-for-later-mutation.tsx} (100%) rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.capture-ref-for-later-mutation.expect.md => error.capture-ref-for-mutation.expect.md} (75%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index 8a65b4709c174..8fee651f8d1ab 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -8,9 +8,11 @@ import {CompilerError, ErrorSeverity} from '../CompilerError'; import { HIRFunction, + Identifier, IdentifierId, Place, SourceLocation, + getHookKindForType, isRefValueType, isUseRefType, } from '../HIR'; @@ -42,25 +44,154 @@ import {isEffectHook} from './ValidateMemoizedEffectDependencies'; * In the future we may reject more cases, based on either object names (`fooRef.current` is likely a ref) * or based on property name alone (`foo.current` might be a ref). */ -type State = { - refs: Set; - refValues: Map; - refAccessingFunctions: Set; -}; + +type RefAccessType = {kind: 'None'} | RefAccessRefType; + +type RefAccessRefType = + | {kind: 'Ref'} + | {kind: 'RefValue'; loc?: SourceLocation} + | {kind: 'Structure'; value: null | RefAccessRefType; fn: null | RefFnType}; + +type RefFnType = {readRefEffect: boolean; returnType: RefAccessType}; + +class Env extends Map { + #changed = false; + + resetChanged(): void { + this.#changed = false; + } + + hasChanged(): boolean { + return this.#changed; + } + + override set(key: IdentifierId, value: RefAccessType): this { + const cur = this.get(key); + const widenedValue = joinRefAccessTypes(value, cur ?? {kind: 'None'}); + if ( + !(cur == null && widenedValue.kind === 'None') && + (cur == null || !tyEqual(cur, widenedValue)) + ) { + this.#changed = true; + } + return super.set(key, widenedValue); + } +} export function validateNoRefAccessInRender(fn: HIRFunction): void { - const state = { - refs: new Set(), - refValues: new Map(), - refAccessingFunctions: new Set(), - }; - validateNoRefAccessInRenderImpl(fn, state).unwrap(); + const env = new Env(); + validateNoRefAccessInRenderImpl(fn, env).unwrap(); +} + +function refTypeOfType(identifier: Identifier): RefAccessType { + if (isRefValueType(identifier)) { + return {kind: 'RefValue'}; + } else if (isUseRefType(identifier)) { + return {kind: 'Ref'}; + } else { + return {kind: 'None'}; + } +} + +function tyEqual(a: RefAccessType, b: RefAccessType): boolean { + if (a.kind !== b.kind) { + return false; + } + switch (a.kind) { + case 'None': + return true; + case 'Ref': + return true; + case 'RefValue': + CompilerError.invariant(b.kind === 'RefValue', { + reason: 'Expected ref value', + loc: null, + }); + return a.loc == b.loc; + case 'Structure': { + CompilerError.invariant(b.kind === 'Structure', { + reason: 'Expected structure', + loc: null, + }); + const fnTypesEqual = + (a.fn === null && b.fn === null) || + (a.fn !== null && + b.fn !== null && + a.fn.readRefEffect === b.fn.readRefEffect && + tyEqual(a.fn.returnType, b.fn.returnType)); + return ( + fnTypesEqual && + (a.value === b.value || + (a.value !== null && b.value !== null && tyEqual(a.value, b.value))) + ); + } + } +} + +function joinRefAccessTypes(...types: Array): RefAccessType { + function joinRefAccessRefTypes( + a: RefAccessRefType, + b: RefAccessRefType, + ): RefAccessRefType { + if (a.kind === 'RefValue') { + return a; + } else if (b.kind === 'RefValue') { + return b; + } else if (a.kind === 'Ref' || b.kind === 'Ref') { + return {kind: 'Ref'}; + } else { + CompilerError.invariant( + a.kind === 'Structure' && b.kind === 'Structure', + { + reason: 'Expected structure', + loc: null, + }, + ); + const fn = + a.fn === null + ? b.fn + : b.fn === null + ? a.fn + : { + readRefEffect: a.fn.readRefEffect || b.fn.readRefEffect, + returnType: joinRefAccessTypes( + a.fn.returnType, + b.fn.returnType, + ), + }; + const value = + a.value === null + ? b.value + : b.value === null + ? a.value + : joinRefAccessRefTypes(a.value, b.value); + return { + kind: 'Structure', + fn, + value, + }; + } + } + + return types.reduce( + (a, b) => { + if (a.kind === 'None') { + return b; + } else if (b.kind === 'None') { + return a; + } else { + return joinRefAccessRefTypes(a, b); + } + }, + {kind: 'None'}, + ); } function validateNoRefAccessInRenderImpl( fn: HIRFunction, - state: State, -): Result { + env: Env, +): Result { + let returnValues: Array = []; let place; for (const param of fn.params) { if (param.kind === 'Identifier') { @@ -68,293 +199,289 @@ function validateNoRefAccessInRenderImpl( } else { place = param.place; } - - if (isRefValueType(place.identifier)) { - state.refValues.set(place.identifier.id, null); - } - if (isUseRefType(place.identifier)) { - state.refs.add(place.identifier.id); - } + const type = refTypeOfType(place.identifier); + env.set(place.identifier.id, type); } - const errors = new CompilerError(); - for (const [, block] of fn.body.blocks) { - for (const phi of block.phis) { - phi.operands.forEach(operand => { - if (state.refs.has(operand.id) || isUseRefType(phi.id)) { - state.refs.add(phi.id.id); - } - const refValue = state.refValues.get(operand.id); - if (refValue !== undefined || isRefValueType(operand)) { - state.refValues.set( - phi.id.id, - refValue ?? state.refValues.get(phi.id.id) ?? null, - ); - } - if (state.refAccessingFunctions.has(operand.id)) { - state.refAccessingFunctions.add(phi.id.id); - } - }); - } - for (const instr of block.instructions) { - for (const operand of eachInstructionValueOperand(instr.value)) { - if (isRefValueType(operand.identifier)) { - CompilerError.invariant(state.refValues.has(operand.identifier.id), { - reason: 'Expected ref value to be in state', - loc: operand.loc, - }); - } - if (isUseRefType(operand.identifier)) { - CompilerError.invariant(state.refs.has(operand.identifier.id), { - reason: 'Expected ref to be in state', - loc: operand.loc, - }); - } + for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) { + env.resetChanged(); + returnValues = []; + const errors = new CompilerError(); + for (const [, block] of fn.body.blocks) { + for (const phi of block.phis) { + env.set( + phi.id.id, + joinRefAccessTypes( + ...Array(...phi.operands.values()).map( + operand => env.get(operand.id) ?? ({kind: 'None'} as const), + ), + ), + ); } - switch (instr.value.kind) { - case 'JsxExpression': - case 'JsxFragment': { - for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoDirectRefValueAccess(errors, operand, state); - } - break; - } - case 'ComputedLoad': - case 'PropertyLoad': { - if (typeof instr.value.property !== 'string') { - validateNoRefValueAccess(errors, state, instr.value.property); - } - if ( - state.refAccessingFunctions.has(instr.value.object.identifier.id) - ) { - state.refAccessingFunctions.add(instr.lvalue.identifier.id); - } - if (state.refs.has(instr.value.object.identifier.id)) { - /* - * Once an object contains a ref at any level, we treat it as a ref. - * If we look something up from it, that value may either be a ref - * or the ref value (or neither), so we conservatively assume it's both. - */ - state.refs.add(instr.lvalue.identifier.id); - state.refValues.set(instr.lvalue.identifier.id, instr.loc); - } - break; - } - case 'LoadContext': - case 'LoadLocal': { - if ( - state.refAccessingFunctions.has(instr.value.place.identifier.id) - ) { - state.refAccessingFunctions.add(instr.lvalue.identifier.id); - } - const refValue = state.refValues.get(instr.value.place.identifier.id); - if (refValue !== undefined) { - state.refValues.set(instr.lvalue.identifier.id, refValue); + for (const instr of block.instructions) { + switch (instr.value.kind) { + case 'JsxExpression': + case 'JsxFragment': { + for (const operand of eachInstructionValueOperand(instr.value)) { + validateNoDirectRefValueAccess(errors, operand, env); + } + break; } - if (state.refs.has(instr.value.place.identifier.id)) { - state.refs.add(instr.lvalue.identifier.id); + case 'ComputedLoad': + case 'PropertyLoad': { + if (typeof instr.value.property !== 'string') { + validateNoDirectRefValueAccess(errors, instr.value.property, env); + } + const objType = env.get(instr.value.object.identifier.id); + let lookupType: null | RefAccessType = null; + if (objType?.kind === 'Structure') { + lookupType = objType.value; + } else if (objType?.kind === 'Ref') { + lookupType = {kind: 'RefValue', loc: instr.loc}; + } + env.set( + instr.lvalue.identifier.id, + lookupType ?? refTypeOfType(instr.lvalue.identifier), + ); + break; } - break; - } - case 'StoreContext': - case 'StoreLocal': { - if ( - state.refAccessingFunctions.has(instr.value.value.identifier.id) - ) { - state.refAccessingFunctions.add( - instr.value.lvalue.place.identifier.id, + case 'LoadContext': + case 'LoadLocal': { + env.set( + instr.lvalue.identifier.id, + env.get(instr.value.place.identifier.id) ?? + refTypeOfType(instr.lvalue.identifier), ); - state.refAccessingFunctions.add(instr.lvalue.identifier.id); + break; } - const refValue = state.refValues.get(instr.value.value.identifier.id); - if ( - refValue !== undefined || - isRefValueType(instr.value.lvalue.place.identifier) - ) { - state.refValues.set( + case 'StoreContext': + case 'StoreLocal': { + env.set( instr.value.lvalue.place.identifier.id, - refValue ?? null, + env.get(instr.value.value.identifier.id) ?? + refTypeOfType(instr.value.lvalue.place.identifier), + ); + env.set( + instr.lvalue.identifier.id, + env.get(instr.value.value.identifier.id) ?? + refTypeOfType(instr.lvalue.identifier), ); - state.refValues.set(instr.lvalue.identifier.id, refValue ?? null); + break; } - if (state.refs.has(instr.value.value.identifier.id)) { - state.refs.add(instr.value.lvalue.place.identifier.id); - state.refs.add(instr.lvalue.identifier.id); + case 'Destructure': { + const objType = env.get(instr.value.value.identifier.id); + let lookupType = null; + if (objType?.kind === 'Structure') { + lookupType = objType.value; + } + env.set( + instr.lvalue.identifier.id, + lookupType ?? refTypeOfType(instr.lvalue.identifier), + ); + for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) { + env.set( + lval.identifier.id, + lookupType ?? refTypeOfType(lval.identifier), + ); + } + break; } - break; - } - case 'Destructure': { - const destructuredFunction = state.refAccessingFunctions.has( - instr.value.value.identifier.id, - ); - const destructuredRef = state.refs.has( - instr.value.value.identifier.id, - ); - for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) { - if (isUseRefType(lval.identifier)) { - state.refs.add(lval.identifier.id); + case 'ObjectMethod': + case 'FunctionExpression': { + let returnType: RefAccessType = {kind: 'None'}; + let readRefEffect = false; + const result = validateNoRefAccessInRenderImpl( + instr.value.loweredFunc.func, + env, + ); + if (result.isOk()) { + returnType = result.unwrap(); + } else if (result.isErr()) { + readRefEffect = true; } - if (destructuredRef || isRefValueType(lval.identifier)) { - state.refs.add(lval.identifier.id); - state.refValues.set(lval.identifier.id, null); + env.set(instr.lvalue.identifier.id, { + kind: 'Structure', + fn: { + readRefEffect, + returnType, + }, + value: null, + }); + break; + } + case 'MethodCall': { + if (!isEffectHook(instr.value.property.identifier)) { + for (const operand of eachInstructionValueOperand(instr.value)) { + const hookKind = getHookKindForType( + fn.env, + instr.value.property.identifier.type, + ); + if (hookKind != null) { + validateNoRefValueAccess(errors, env, operand); + } else { + validateNoRefAccess(errors, env, operand, operand.loc); + } + } } - if (destructuredFunction) { - state.refAccessingFunctions.add(lval.identifier.id); + validateNoRefValueAccess(errors, env, instr.value.receiver); + const methType = env.get(instr.value.property.identifier.id); + let returnType: RefAccessType = {kind: 'None'}; + if (methType?.kind === 'Structure' && methType.fn !== null) { + returnType = methType.fn.returnType; } + env.set(instr.lvalue.identifier.id, returnType); + break; } - break; - } - case 'ObjectMethod': - case 'FunctionExpression': { - if ( - /* - * check if the function expression accesses a ref *or* some other - * function which accesses a ref - */ - [...eachInstructionValueOperand(instr.value)].some( - operand => - state.refValues.has(operand.identifier.id) || - state.refAccessingFunctions.has(operand.identifier.id), - ) || - // check for cases where .current is accessed through an aliased ref - ([...eachInstructionValueOperand(instr.value)].some(operand => - state.refs.has(operand.identifier.id), - ) && - validateNoRefAccessInRenderImpl( - instr.value.loweredFunc.func, - state, - ).isErr()) - ) { - // This function expression unconditionally accesses a ref - state.refAccessingFunctions.add(instr.lvalue.identifier.id); + case 'CallExpression': { + const callee = instr.value.callee; + const hookKind = getHookKindForType(fn.env, callee.identifier.type); + const isUseEffect = isEffectHook(callee.identifier); + let returnType: RefAccessType = {kind: 'None'}; + if (!isUseEffect) { + // Report a more precise error when calling a local function that accesses a ref + const fnType = env.get(instr.value.callee.identifier.id); + if (fnType?.kind === 'Structure' && fnType.fn !== null) { + returnType = fnType.fn.returnType; + if (fnType.fn.readRefEffect) { + errors.push({ + severity: ErrorSeverity.InvalidReact, + reason: + 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)', + loc: callee.loc, + description: + callee.identifier.name !== null && + callee.identifier.name.kind === 'named' + ? `Function \`${callee.identifier.name.value}\` accesses a ref` + : null, + suggestions: null, + }); + } + } + for (const operand of eachInstructionValueOperand(instr.value)) { + if (hookKind != null) { + validateNoRefValueAccess(errors, env, operand); + } else { + validateNoRefAccess(errors, env, operand, operand.loc); + } + } + } + env.set(instr.lvalue.identifier.id, returnType); + break; } - break; - } - case 'MethodCall': { - if (!isEffectHook(instr.value.property.identifier)) { + case 'ObjectExpression': + case 'ArrayExpression': { + const types: Array = []; for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefAccess(errors, state, operand, operand.loc); + validateNoDirectRefValueAccess(errors, operand, env); + types.push(env.get(operand.identifier.id) ?? {kind: 'None'}); } - } - break; - } - case 'CallExpression': { - const callee = instr.value.callee; - const isUseEffect = isEffectHook(callee.identifier); - if (!isUseEffect) { - // Report a more precise error when calling a local function that accesses a ref - if (state.refAccessingFunctions.has(callee.identifier.id)) { - errors.push({ - severity: ErrorSeverity.InvalidReact, - reason: - 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: callee.loc, - description: - callee.identifier.name !== null && - callee.identifier.name.kind === 'named' - ? `Function \`${callee.identifier.name.value}\` accesses a ref` - : null, - suggestions: null, + const value = joinRefAccessTypes(...types); + if (value.kind === 'None') { + env.set(instr.lvalue.identifier.id, {kind: 'None'}); + } else { + env.set(instr.lvalue.identifier.id, { + kind: 'Structure', + value, + fn: null, }); } + break; + } + case 'PropertyDelete': + case 'PropertyStore': + case 'ComputedDelete': + case 'ComputedStore': { + validateNoRefAccess(errors, env, instr.value.object, instr.loc); for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefAccess( - errors, - state, - operand, - state.refValues.get(operand.identifier.id) ?? operand.loc, - ); + if (operand === instr.value.object) { + continue; + } + validateNoRefValueAccess(errors, env, operand); } + break; } - break; - } - case 'ObjectExpression': - case 'ArrayExpression': { - for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoDirectRefValueAccess(errors, operand, state); - if (state.refAccessingFunctions.has(operand.identifier.id)) { - state.refAccessingFunctions.add(instr.lvalue.identifier.id); - } - if (state.refs.has(operand.identifier.id)) { - state.refs.add(instr.lvalue.identifier.id); - } - const refValue = state.refValues.get(operand.identifier.id); - if (refValue !== undefined) { - state.refValues.set(instr.lvalue.identifier.id, refValue); + case 'StartMemoize': + case 'FinishMemoize': + break; + default: { + for (const operand of eachInstructionValueOperand(instr.value)) { + validateNoRefValueAccess(errors, env, operand); } + break; } - break; } - case 'PropertyDelete': - case 'PropertyStore': - case 'ComputedDelete': - case 'ComputedStore': { - validateNoRefAccess( - errors, - state, - instr.value.object, - state.refValues.get(instr.value.object.identifier.id) ?? instr.loc, + if (isUseRefType(instr.lvalue.identifier)) { + env.set( + instr.lvalue.identifier.id, + joinRefAccessTypes( + env.get(instr.lvalue.identifier.id) ?? {kind: 'None'}, + {kind: 'Ref'}, + ), ); - for (const operand of eachInstructionValueOperand(instr.value)) { - if (operand === instr.value.object) { - continue; - } - validateNoRefValueAccess(errors, state, operand); - } - break; } - case 'StartMemoize': - case 'FinishMemoize': - break; - default: { - for (const operand of eachInstructionValueOperand(instr.value)) { - validateNoRefValueAccess(errors, state, operand); - } - break; + if (isRefValueType(instr.lvalue.identifier)) { + env.set( + instr.lvalue.identifier.id, + joinRefAccessTypes( + env.get(instr.lvalue.identifier.id) ?? {kind: 'None'}, + {kind: 'RefValue', loc: instr.loc}, + ), + ); } } - if (isUseRefType(instr.lvalue.identifier)) { - state.refs.add(instr.lvalue.identifier.id); - } - if ( - isRefValueType(instr.lvalue.identifier) && - !state.refValues.has(instr.lvalue.identifier.id) - ) { - state.refValues.set(instr.lvalue.identifier.id, instr.loc); + for (const operand of eachTerminalOperand(block.terminal)) { + if (block.terminal.kind !== 'return') { + validateNoRefValueAccess(errors, env, operand); + } else { + // Allow functions containing refs to be returned, but not direct ref values + validateNoDirectRefValueAccess(errors, operand, env); + returnValues.push(env.get(operand.identifier.id)); + } } } - for (const operand of eachTerminalOperand(block.terminal)) { - if (block.terminal.kind !== 'return') { - validateNoRefValueAccess(errors, state, operand); - } else { - // Allow functions containing refs to be returned, but not direct ref values - validateNoDirectRefValueAccess(errors, operand, state); - } + + if (errors.hasErrors()) { + return Err(errors); } } - if (errors.hasErrors()) { - return Err(errors); - } else { - return Ok(undefined); + CompilerError.invariant(!env.hasChanged(), { + reason: 'Ref type environment did not converge', + loc: null, + }); + + return Ok( + joinRefAccessTypes( + ...returnValues.filter((env): env is RefAccessType => env !== undefined), + ), + ); +} + +function destructure( + type: RefAccessType | undefined, +): RefAccessType | undefined { + if (type?.kind === 'Structure' && type.value !== null) { + return destructure(type.value); } + return type; } function validateNoRefValueAccess( errors: CompilerError, - state: State, + env: Env, operand: Place, ): void { + const type = destructure(env.get(operand.identifier.id)); if ( - state.refValues.has(operand.identifier.id) || - state.refAccessingFunctions.has(operand.identifier.id) + type?.kind === 'RefValue' || + (type?.kind === 'Structure' && type.fn?.readRefEffect) ) { errors.push({ severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: state.refValues.get(operand.identifier.id) ?? operand.loc, + loc: (type.kind === 'RefValue' && type.loc) || operand.loc, description: operand.identifier.name !== null && operand.identifier.name.kind === 'named' @@ -367,20 +494,21 @@ function validateNoRefValueAccess( function validateNoRefAccess( errors: CompilerError, - state: State, + env: Env, operand: Place, loc: SourceLocation, ): void { + const type = destructure(env.get(operand.identifier.id)); if ( - state.refs.has(operand.identifier.id) || - state.refValues.has(operand.identifier.id) || - state.refAccessingFunctions.has(operand.identifier.id) + type?.kind === 'Ref' || + type?.kind === 'RefValue' || + (type?.kind === 'Structure' && type.fn?.readRefEffect) ) { errors.push({ severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: loc, + loc: (type.kind === 'RefValue' && type.loc) || loc, description: operand.identifier.name !== null && operand.identifier.name.kind === 'named' @@ -394,14 +522,15 @@ function validateNoRefAccess( function validateNoDirectRefValueAccess( errors: CompilerError, operand: Place, - state: State, + env: Env, ): void { - if (state.refValues.has(operand.identifier.id)) { + const type = destructure(env.get(operand.identifier.id)); + if (type?.kind === 'RefValue') { errors.push({ severity: ErrorSeverity.InvalidReact, reason: 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: state.refValues.get(operand.identifier.id) ?? operand.loc, + loc: type.loc ?? operand.loc, description: operand.identifier.name !== null && operand.identifier.name.kind === 'named' diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md new file mode 100644 index 0000000000000..b7371108d5867 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.expect.md @@ -0,0 +1,69 @@ + +## Input + +```javascript +import {useRef} from 'react'; +import {addOne} from 'shared-runtime'; + +function useKeyCommand() { + const currentPosition = useRef(0); + const handleKey = direction => () => { + const position = currentPosition.current; + const nextPosition = direction === 'left' ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + const moveLeft = { + handler: handleKey('left'), + }; + const moveRight = { + handler: handleKey('right'), + }; + return [moveLeft, moveRight]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useRef } from "react"; +import { addOne } from "shared-runtime"; + +function useKeyCommand() { + const $ = _c(1); + const currentPosition = useRef(0); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + const handleKey = (direction) => () => { + const position = currentPosition.current; + const nextPosition = direction === "left" ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + + const moveLeft = { handler: handleKey("left") }; + + const moveRight = { handler: handleKey("right") }; + + t0 = [moveLeft, moveRight]; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; + +``` + +### Eval output +(kind: ok) [{"handler":"[[ function params=0 ]]"},{"handler":"[[ function params=0 ]]"}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.tsx similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.tsx rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capture-ref-for-later-mutation.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md similarity index 75% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md index 52350036257d0..cff34e3449376 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-later-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.expect.md @@ -13,10 +13,10 @@ function useKeyCommand() { currentPosition.current = nextPosition; }; const moveLeft = { - handler: handleKey('left'), + handler: handleKey('left')(), }; const moveRight = { - handler: handleKey('right'), + handler: handleKey('right')(), }; return [moveLeft, moveRight]; } @@ -34,8 +34,8 @@ export const FIXTURE_ENTRYPOINT = { ``` 10 | }; 11 | const moveLeft = { -> 12 | handler: handleKey('left'), - | ^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) +> 12 | handler: handleKey('left')(), + | ^^^^^^^^^^^^^^^^^ InvalidReact: This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (12:12) @@ -44,7 +44,7 @@ InvalidReact: This function accesses a ref value (the `current` property), which InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (15:15) 13 | }; 14 | const moveRight = { - 15 | handler: handleKey('right'), + 15 | handler: handleKey('right')(), ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.tsx new file mode 100644 index 0000000000000..41e117ed15e80 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.capture-ref-for-mutation.tsx @@ -0,0 +1,23 @@ +import {useRef} from 'react'; +import {addOne} from 'shared-runtime'; + +function useKeyCommand() { + const currentPosition = useRef(0); + const handleKey = direction => () => { + const position = currentPosition.current; + const nextPosition = direction === 'left' ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + const moveLeft = { + handler: handleKey('left')(), + }; + const moveRight = { + handler: handleKey('right')(), + }; + return [moveLeft, moveRight]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md new file mode 100644 index 0000000000000..54184be0f3f38 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.expect.md @@ -0,0 +1,70 @@ + +## Input + +```javascript +// @enableReactiveScopesInHIR:false +import {useRef} from 'react'; +import {addOne} from 'shared-runtime'; + +function useKeyCommand() { + const currentPosition = useRef(0); + const handleKey = direction => () => { + const position = currentPosition.current; + const nextPosition = direction === 'left' ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + const moveLeft = { + handler: handleKey('left'), + }; + const moveRight = { + handler: handleKey('right'), + }; + return [moveLeft, moveRight]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableReactiveScopesInHIR:false +import { useRef } from "react"; +import { addOne } from "shared-runtime"; + +function useKeyCommand() { + const $ = _c(1); + const currentPosition = useRef(0); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + const handleKey = (direction) => () => { + const position = currentPosition.current; + const nextPosition = direction === "left" ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + + const moveLeft = { handler: handleKey("left") }; + + const moveRight = { handler: handleKey("right") }; + + t0 = [moveLeft, moveRight]; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; + +``` + +### Eval output +(kind: ok) [{"handler":"[[ function params=0 ]]"},{"handler":"[[ function params=0 ]]"}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.tsx new file mode 100644 index 0000000000000..6f27dfe07fb33 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/original-reactive-scopes-fork/capture-ref-for-later-mutation.tsx @@ -0,0 +1,24 @@ +// @enableReactiveScopesInHIR:false +import {useRef} from 'react'; +import {addOne} from 'shared-runtime'; + +function useKeyCommand() { + const currentPosition = useRef(0); + const handleKey = direction => () => { + const position = currentPosition.current; + const nextPosition = direction === 'left' ? addOne(position) : position; + currentPosition.current = nextPosition; + }; + const moveLeft = { + handler: handleKey('left'), + }; + const moveRight = { + handler: handleKey('right'), + }; + return [moveLeft, moveRight]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useKeyCommand, + params: [], +}; From e78c9362c014dccaed5ff193106e44d7d072dc32 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Mon, 16 Sep 2024 10:53:34 -0700 Subject: [PATCH 154/426] [compiler] Allow all hooks to take callbacks which access refs, but ban hooks from taking direct ref value arguments Summary: This brings the behavior of ref mutation within hook callbacks into alignment with the behavior of global mutations--that is, we allow all hooks to take callbacks that may mutate a ref. This is potentially unsafe if the hook eagerly calls its callback, but the alternative is excessively limiting (and inconsistent with other enforcement). This also bans *directly* passing a ref.current value to a hook, which was previously allowed. ghstack-source-id: e66ce7123ecf4a905adab957970d0ee5d41245e0 Pull Request resolved: https://github.com/facebook/react/pull/30917 --- .../src/HIR/Globals.ts | 11 +++ .../src/HIR/ObjectShape.ts | 1 + .../Validation/ValidateNoRefAccesInRender.ts | 78 +++++++------------ .../compiler/error.hook-ref-value.expect.md | 34 ++++++++ .../fixtures/compiler/error.hook-ref-value.js | 11 +++ .../compiler/hook-ref-callback.expect.md | 54 +++++++++++++ .../fixtures/compiler/hook-ref-callback.js | 15 ++++ .../useImperativeHandle-ref-mutate.expect.md | 66 ++++++++++++++++ .../useImperativeHandle-ref-mutate.js | 19 +++++ 9 files changed, 238 insertions(+), 51 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts index c923882900cc2..1128c51caeb58 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts @@ -364,6 +364,17 @@ const REACT_APIS: Array<[string, BuiltInType]> = [ returnValueKind: ValueKind.Mutable, }), ], + [ + 'useImperativeHandle', + addHook(DEFAULT_SHAPES, { + positionalParams: [], + restParam: Effect.Freeze, + returnType: {kind: 'Primitive'}, + calleeEffect: Effect.Read, + hookKind: 'useImperativeHandle', + returnValueKind: ValueKind.Frozen, + }), + ], [ 'useMemo', addHook(DEFAULT_SHAPES, { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts index 04f85e496453a..14f809f2c4082 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts @@ -127,6 +127,7 @@ export type HookKind = | 'useMemo' | 'useCallback' | 'useTransition' + | 'useImperativeHandle' | 'Custom'; /* diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index 8fee651f8d1ab..5f98b0ee8e4af 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -22,7 +22,6 @@ import { eachTerminalOperand, } from '../HIR/visitors'; import {Err, Ok, Result} from '../Utils/Result'; -import {isEffectHook} from './ValidateMemoizedEffectDependencies'; /** * Validates that a function does not access a ref value during render. This includes a partial check @@ -310,60 +309,37 @@ function validateNoRefAccessInRenderImpl( }); break; } - case 'MethodCall': { - if (!isEffectHook(instr.value.property.identifier)) { - for (const operand of eachInstructionValueOperand(instr.value)) { - const hookKind = getHookKindForType( - fn.env, - instr.value.property.identifier.type, - ); - if (hookKind != null) { - validateNoRefValueAccess(errors, env, operand); - } else { - validateNoRefAccess(errors, env, operand, operand.loc); - } - } - } - validateNoRefValueAccess(errors, env, instr.value.receiver); - const methType = env.get(instr.value.property.identifier.id); - let returnType: RefAccessType = {kind: 'None'}; - if (methType?.kind === 'Structure' && methType.fn !== null) { - returnType = methType.fn.returnType; - } - env.set(instr.lvalue.identifier.id, returnType); - break; - } + case 'MethodCall': case 'CallExpression': { - const callee = instr.value.callee; + const callee = + instr.value.kind === 'CallExpression' + ? instr.value.callee + : instr.value.property; const hookKind = getHookKindForType(fn.env, callee.identifier.type); - const isUseEffect = isEffectHook(callee.identifier); let returnType: RefAccessType = {kind: 'None'}; - if (!isUseEffect) { - // Report a more precise error when calling a local function that accesses a ref - const fnType = env.get(instr.value.callee.identifier.id); - if (fnType?.kind === 'Structure' && fnType.fn !== null) { - returnType = fnType.fn.returnType; - if (fnType.fn.readRefEffect) { - errors.push({ - severity: ErrorSeverity.InvalidReact, - reason: - 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)', - loc: callee.loc, - description: - callee.identifier.name !== null && - callee.identifier.name.kind === 'named' - ? `Function \`${callee.identifier.name.value}\` accesses a ref` - : null, - suggestions: null, - }); - } + const fnType = env.get(callee.identifier.id); + if (fnType?.kind === 'Structure' && fnType.fn !== null) { + returnType = fnType.fn.returnType; + if (fnType.fn.readRefEffect) { + errors.push({ + severity: ErrorSeverity.InvalidReact, + reason: + 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)', + loc: callee.loc, + description: + callee.identifier.name !== null && + callee.identifier.name.kind === 'named' + ? `Function \`${callee.identifier.name.value}\` accesses a ref` + : null, + suggestions: null, + }); } - for (const operand of eachInstructionValueOperand(instr.value)) { - if (hookKind != null) { - validateNoRefValueAccess(errors, env, operand); - } else { - validateNoRefAccess(errors, env, operand, operand.loc); - } + } + for (const operand of eachInstructionValueOperand(instr.value)) { + if (hookKind != null) { + validateNoDirectRefValueAccess(errors, operand, env); + } else { + validateNoRefAccess(errors, env, operand, operand.loc); } } env.set(instr.lvalue.identifier.id, returnType); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md new file mode 100644 index 0000000000000..d92d918fe9f3c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.expect.md @@ -0,0 +1,34 @@ + +## Input + +```javascript +import {useEffect, useRef} from 'react'; + +function Component(props) { + const ref = useRef(); + useEffect(() => {}, [ref.current]); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + + +## Error + +``` + 3 | function Component(props) { + 4 | const ref = useRef(); +> 5 | useEffect(() => {}, [ref.current]); + | ^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5) + 6 | } + 7 | + 8 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.js new file mode 100644 index 0000000000000..3276e4b4b44a9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hook-ref-value.js @@ -0,0 +1,11 @@ +import {useEffect, useRef} from 'react'; + +function Component(props) { + const ref = useRef(); + useEffect(() => {}, [ref.current]); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.expect.md new file mode 100644 index 0000000000000..3056a60a3a977 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.expect.md @@ -0,0 +1,54 @@ + +## Input + +```javascript +import {useEffect, useRef} from 'react'; + +function Component(props) { + const ref = useRef(); + useFoo(() => { + ref.current = 42; + }); +} + +function useFoo(x) {} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useEffect, useRef } from "react"; + +function Component(props) { + const $ = _c(1); + const ref = useRef(); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = () => { + ref.current = 42; + }; + $[0] = t0; + } else { + t0 = $[0]; + } + useFoo(t0); +} + +function useFoo(x) {} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + +### Eval output +(kind: ok) \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.js new file mode 100644 index 0000000000000..ab496e0adf012 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-ref-callback.js @@ -0,0 +1,15 @@ +import {useEffect, useRef} from 'react'; + +function Component(props) { + const ref = useRef(); + useFoo(() => { + ref.current = 42; + }); +} + +function useFoo(x) {} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md new file mode 100644 index 0000000000000..30d96038d43ca --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.expect.md @@ -0,0 +1,66 @@ + +## Input + +```javascript +// @flow + +import {useImperativeHandle, useRef} from 'react'; + +component Component(prop: number) { + const ref1 = useRef(null); + const ref2 = useRef(1); + useImperativeHandle(ref1, () => { + const precomputed = prop + ref2.current; + return { + foo: () => prop + ref2.current + precomputed, + }; + }, [prop]); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{prop: 1}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; + +import { useImperativeHandle, useRef } from "react"; + +function Component(t0) { + const $ = _c(3); + const { prop } = t0; + const ref1 = useRef(null); + const ref2 = useRef(1); + let t1; + let t2; + if ($[0] !== prop) { + t1 = () => { + const precomputed = prop + ref2.current; + return { foo: () => prop + ref2.current + precomputed }; + }; + + t2 = [prop]; + $[0] = prop; + $[1] = t1; + $[2] = t2; + } else { + t1 = $[1]; + t2 = $[2]; + } + useImperativeHandle(ref1, t1, t2); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ prop: 1 }], +}; + +``` + +### Eval output +(kind: ok) \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.js new file mode 100644 index 0000000000000..63d090ddd8164 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useImperativeHandle-ref-mutate.js @@ -0,0 +1,19 @@ +// @flow + +import {useImperativeHandle, useRef} from 'react'; + +component Component(prop: number) { + const ref1 = useRef(null); + const ref2 = useRef(1); + useImperativeHandle(ref1, () => { + const precomputed = prop + ref2.current; + return { + foo: () => prop + ref2.current + precomputed, + }; + }, [prop]); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{prop: 1}], +}; From d7167c35059bc6a0ad84eb34e65b3b66328d5dd8 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Mon, 16 Sep 2024 11:12:58 -0700 Subject: [PATCH 155/426] [compiler] Implement support for hoisted and recursive functions Summary: Introduces a new binding kind for functions that allows them to be hoisted. Also has the result of causing all nested function declarations to be outputted as function declarations, not as let bindings. ghstack-source-id: fa40d4909fb3d30c23691e36510ebb3c3cc41053 Pull Request resolved: https://github.com/facebook/react/pull/30922 --- .../src/HIR/BuildHIR.ts | 30 ++++--- .../src/HIR/HIR.ts | 6 +- .../src/HIR/PrintHIR.ts | 6 ++ .../ReactiveScopes/CodegenReactiveFunction.ts | 85 +++++++++---------- .../ReactiveScopes/PruneHoistedContexts.ts | 11 +++ ...ror.hoisted-function-declaration.expect.md | 29 ------- .../error.hoisted-function-declaration.js | 8 -- ...ting-simple-function-declaration.expect.md | 14 +-- .../error.todo-hoist-function-decls.expect.md | 14 +-- ...do-recursive-function-expression.expect.md | 30 ------- .../hoisted-function-declaration.expect.md | 63 ++++++++++++++ .../compiler/hoisted-function-declaration.js | 19 +++++ .../recursive-function-expression.expect.md | 53 ++++++++++++ ...on.js => recursive-function-expression.js} | 5 ++ 14 files changed, 234 insertions(+), 139 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{error.todo-recursive-function-expression.js => recursive-function-expression.js} (67%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index 7fb12d4624c10..a179224a7705f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -420,7 +420,19 @@ function lowerStatement( // Already hoisted continue; } - if (!binding.path.isVariableDeclarator()) { + + let kind: + | InstructionKind.Let + | InstructionKind.HoistedConst + | InstructionKind.HoistedLet + | InstructionKind.HoistedFunction; + if (binding.kind === 'const' || binding.kind === 'var') { + kind = InstructionKind.HoistedConst; + } else if (binding.kind === 'let') { + kind = InstructionKind.HoistedLet; + } else if (binding.path.isFunctionDeclaration()) { + kind = InstructionKind.HoistedFunction; + } else if (!binding.path.isVariableDeclarator()) { builder.errors.push({ severity: ErrorSeverity.Todo, reason: 'Unsupported declaration type for hoisting', @@ -429,11 +441,7 @@ function lowerStatement( loc: id.parentPath.node.loc ?? GeneratedSource, }); continue; - } else if ( - binding.kind !== 'const' && - binding.kind !== 'var' && - binding.kind !== 'let' - ) { + } else { builder.errors.push({ severity: ErrorSeverity.Todo, reason: 'Handle non-const declarations for hoisting', @@ -443,6 +451,7 @@ function lowerStatement( }); continue; } + const identifier = builder.resolveIdentifier(id); CompilerError.invariant(identifier.kind === 'Identifier', { reason: @@ -456,13 +465,6 @@ function lowerStatement( reactive: false, loc: id.node.loc ?? GeneratedSource, }; - const kind = - // Avoid double errors on var declarations, which we do not plan to support anyways - binding.kind === 'const' || binding.kind === 'var' - ? InstructionKind.HoistedConst - : binding.kind === 'let' - ? InstructionKind.HoistedLet - : assertExhaustive(binding.kind, 'Unexpected binding kind'); lowerValueToTemporary(builder, { kind: 'DeclareContext', lvalue: { @@ -999,7 +1001,7 @@ function lowerStatement( lowerAssignment( builder, stmt.node.loc ?? GeneratedSource, - InstructionKind.Let, + InstructionKind.Function, id, fn, 'Assignment', diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 930dd79f2fd59..30408ab032b35 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -746,6 +746,9 @@ export enum InstructionKind { // hoisted const declarations HoistedLet = 'HoistedLet', + + HoistedFunction = 'HoistedFunction', + Function = 'Function', } function _staticInvariantInstructionValueHasLocation( @@ -865,7 +868,8 @@ export type InstructionValue = kind: | InstructionKind.Let | InstructionKind.HoistedConst - | InstructionKind.HoistedLet; + | InstructionKind.HoistedLet + | InstructionKind.HoistedFunction; place: Place; }; loc: SourceLocation; diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index c2db20c5099a1..c88d3bf773898 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -765,6 +765,12 @@ export function printLValue(lval: LValue): string { case InstructionKind.HoistedLet: { return `HoistedLet ${lvalue}$`; } + case InstructionKind.Function: { + return `Function ${lvalue}$`; + } + case InstructionKind.HoistedFunction: { + return `HoistedFunction ${lvalue}$`; + } default: { assertExhaustive(lval.kind, `Unexpected lvalue kind \`${lval.kind}\``); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index 2df7b5ed1c7fd..297c7712546c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -981,22 +981,12 @@ function codegenTerminal( suggestions: null, }); case InstructionKind.Catch: - CompilerError.invariant(false, { - reason: 'Unexpected catch variable as for..in collection', - description: null, - loc: iterableItem.loc, - suggestions: null, - }); case InstructionKind.HoistedConst: - CompilerError.invariant(false, { - reason: 'Unexpected HoistedConst variable in for..in collection', - description: null, - loc: iterableItem.loc, - suggestions: null, - }); case InstructionKind.HoistedLet: + case InstructionKind.HoistedFunction: + case InstructionKind.Function: CompilerError.invariant(false, { - reason: 'Unexpected HoistedLet variable in for..in collection', + reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..in collection`, description: null, loc: iterableItem.loc, suggestions: null, @@ -1075,30 +1065,13 @@ function codegenTerminal( varDeclKind = 'let' as const; break; case InstructionKind.Reassign: - CompilerError.invariant(false, { - reason: - 'Destructure should never be Reassign as it would be an Object/ArrayPattern', - description: null, - loc: iterableItem.loc, - suggestions: null, - }); case InstructionKind.Catch: - CompilerError.invariant(false, { - reason: 'Unexpected catch variable as for..of collection', - description: null, - loc: iterableItem.loc, - suggestions: null, - }); case InstructionKind.HoistedConst: - CompilerError.invariant(false, { - reason: 'Unexpected HoistedConst variable in for..of collection', - description: null, - loc: iterableItem.loc, - suggestions: null, - }); case InstructionKind.HoistedLet: + case InstructionKind.HoistedFunction: + case InstructionKind.Function: CompilerError.invariant(false, { - reason: 'Unexpected HoistedLet variable in for..of collection', + reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..of collection`, description: null, loc: iterableItem.loc, suggestions: null, @@ -1261,6 +1234,35 @@ function codegenInstructionNullable( t.variableDeclarator(codegenLValue(cx, lvalue), value), ]); } + case InstructionKind.Function: { + CompilerError.invariant(instr.lvalue === null, { + reason: `Function declaration cannot be referenced as an expression`, + description: null, + loc: instr.value.loc, + suggestions: null, + }); + const genLvalue = codegenLValue(cx, lvalue); + CompilerError.invariant(genLvalue.type === 'Identifier', { + reason: 'Expected an identifier as a function declaration lvalue', + description: null, + loc: instr.value.loc, + suggestions: null, + }); + CompilerError.invariant(value?.type === 'FunctionExpression', { + reason: 'Expected a function as a function declaration value', + description: null, + loc: instr.value.loc, + suggestions: null, + }); + return createFunctionDeclaration( + instr.loc, + genLvalue, + value.params, + value.body, + value.generator, + value.async, + ); + } case InstructionKind.Let: { CompilerError.invariant(instr.lvalue === null, { reason: `Const declaration cannot be referenced as an expression`, @@ -1303,19 +1305,11 @@ function codegenInstructionNullable( case InstructionKind.Catch: { return t.emptyStatement(); } - case InstructionKind.HoistedLet: { - CompilerError.invariant(false, { - reason: - 'Expected HoistedLet to have been pruned in PruneHoistedContexts', - description: null, - loc: instr.loc, - suggestions: null, - }); - } - case InstructionKind.HoistedConst: { + case InstructionKind.HoistedLet: + case InstructionKind.HoistedConst: + case InstructionKind.HoistedFunction: { CompilerError.invariant(false, { - reason: - 'Expected HoistedConsts to have been pruned in PruneHoistedContexts', + reason: `Expected ${kind} to have been pruned in PruneHoistedContexts`, description: null, loc: instr.loc, suggestions: null, @@ -1486,6 +1480,7 @@ const createBinaryExpression = withLoc(t.binaryExpression); const createExpressionStatement = withLoc(t.expressionStatement); const _createLabelledStatement = withLoc(t.labeledStatement); const createVariableDeclaration = withLoc(t.variableDeclaration); +const createFunctionDeclaration = withLoc(t.functionDeclaration); const _createWhileStatement = withLoc(t.whileStatement); const createTaggedTemplateExpression = withLoc(t.taggedTemplateExpression); const createLogicalExpression = withLoc(t.logicalExpression); diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts index 1df211afc3ae4..07b099c2ea5fe 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PruneHoistedContexts.ts @@ -57,6 +57,17 @@ class Visitor extends ReactiveFunctionTransform { return {kind: 'remove'}; } + if ( + instruction.value.kind === 'DeclareContext' && + instruction.value.lvalue.kind === 'HoistedFunction' + ) { + state.set( + instruction.value.lvalue.place.identifier.declarationId, + InstructionKind.Function, + ); + return {kind: 'remove'}; + } + if ( instruction.value.kind === 'StoreContext' && state.has(instruction.value.lvalue.place.identifier.declarationId) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md deleted file mode 100644 index d2e51d07256e6..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.expect.md +++ /dev/null @@ -1,29 +0,0 @@ - -## Input - -```javascript -function component(a) { - let t = {a}; - x(t); // hoisted call - function x(p) { - p.foo(); - } - return t; -} - -``` - - -## Error - -``` - 1 | function component(a) { - 2 | let t = {a}; -> 3 | x(t); // hoisted call - | ^^^^ Todo: Unsupported declaration type for hoisting. variable "x" declared with FunctionDeclaration (3:3) - 4 | function x(p) { - 5 | p.foo(); - 6 | } -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js deleted file mode 100644 index 3b0586d4376e6..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisted-function-declaration.js +++ /dev/null @@ -1,8 +0,0 @@ -function component(a) { - let t = {a}; - x(t); // hoisted call - function x(p) { - p.foo(); - } - return t; -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md index 91f8e67d0c698..2045ee7901e96 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoisting-simple-function-declaration.expect.md @@ -24,13 +24,13 @@ export const FIXTURE_ENTRYPOINT = { ## Error ``` - 3 | return x; - 4 | } -> 5 | return baz(); // OK: FuncDecls are HoistableDeclarations that have both declaration and value hoisting - | ^^^^^ Todo: Unsupported declaration type for hoisting. variable "baz" declared with FunctionDeclaration (5:5) - 6 | function baz() { - 7 | return bar(); - 8 | } + 5 | return baz(); // OK: FuncDecls are HoistableDeclarations that have both declaration and value hoisting + 6 | function baz() { +> 7 | return bar(); + | ^^^ Todo: Support functions with unreachable code that may contain hoisted declarations (7:7) + 8 | } + 9 | } + 10 | ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-hoist-function-decls.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-hoist-function-decls.expect.md index 02b2060e84e7e..b3aa848f1c745 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-hoist-function-decls.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-hoist-function-decls.expect.md @@ -16,11 +16,15 @@ function Component() { ``` 1 | function Component() { -> 2 | return get2(); - | ^^^^^^ Todo: Unsupported declaration type for hoisting. variable "get2" declared with FunctionDeclaration (2:2) - 3 | function get2() { - 4 | return 2; - 5 | } + 2 | return get2(); +> 3 | function get2() { + | ^^^^^^^^^^^^^^^^^ +> 4 | return 2; + | ^^^^^^^^^^^^^ +> 5 | } + | ^^^^ Todo: Support functions with unreachable code that may contain hoisted declarations (3:5) + 6 | } + 7 | ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.expect.md deleted file mode 100644 index d4d09dfeae9b0..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.expect.md +++ /dev/null @@ -1,30 +0,0 @@ - -## Input - -```javascript -function Component() { - function callback(x) { - if (x == 0) { - return null; - } - return callback(x - 1); - } - return callback(10); -} - -``` - - -## Error - -``` - 4 | return null; - 5 | } -> 6 | return callback(x - 1); - | ^^^^^^^^^^^^^^^ Todo: Unsupported declaration type for hoisting. variable "callback" declared with FunctionDeclaration (6:6) - 7 | } - 8 | return callback(10); - 9 | } -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.expect.md new file mode 100644 index 0000000000000..aa3246614ab41 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.expect.md @@ -0,0 +1,63 @@ + +## Input + +```javascript +function component(a) { + let t = {a}; + x(t); // hoisted call + function x(p) { + p.a.foo(); + } + return t; +} + +export const FIXTURE_ENTRYPOINT = { + fn: component, + params: [ + { + foo: () => { + console.log(42); + }, + }, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function component(a) { + const $ = _c(2); + let t; + if ($[0] !== a) { + t = { a }; + x(t); + function x(p) { + p.a.foo(); + } + $[0] = a; + $[1] = t; + } else { + t = $[1]; + } + return t; +} + +export const FIXTURE_ENTRYPOINT = { + fn: component, + params: [ + { + foo: () => { + console.log(42); + }, + }, + ], +}; + +``` + +### Eval output +(kind: ok) {"a":{"foo":"[[ function params=0 ]]"}} +logs: [42] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.js new file mode 100644 index 0000000000000..6fe6dc04cc97b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisted-function-declaration.js @@ -0,0 +1,19 @@ +function component(a) { + let t = {a}; + x(t); // hoisted call + function x(p) { + p.a.foo(); + } + return t; +} + +export const FIXTURE_ENTRYPOINT = { + fn: component, + params: [ + { + foo: () => { + console.log(42); + }, + }, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.expect.md new file mode 100644 index 0000000000000..bc46c1b85578b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.expect.md @@ -0,0 +1,53 @@ + +## Input + +```javascript +function Component() { + function callback(x) { + if (x == 0) { + return null; + } + return callback(x - 1); + } + return callback(10); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + function callback(x) { + if (x == 0) { + return null; + } + return callback(x - 1); + } + + t0 = callback(10); + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + +### Eval output +(kind: ok) null \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.js similarity index 67% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.js index f1b95e5105761..5d50de75bae50 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-recursive-function-expression.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/recursive-function-expression.js @@ -7,3 +7,8 @@ function Component() { } return callback(10); } + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; From 8152e5cd27721e792f395c0b62c8a7769a54777a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 16 Sep 2024 15:00:17 -0400 Subject: [PATCH 156/426] Remove execution context check from shouldProfile (#30971) I don't know why this is here since all these callsites are within the CommitWork/CommitEffects helpers. This should help with inlining. --- .../react-reconciler/src/ReactFiberCommitEffects.js | 8 ++------ .../react-reconciler/src/ReactFiberCommitWork.js | 12 ++---------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitEffects.js b/packages/react-reconciler/src/ReactFiberCommitEffects.js index af5762df2110a..dde2479ba8638 100644 --- a/packages/react-reconciler/src/ReactFiberCommitEffects.js +++ b/packages/react-reconciler/src/ReactFiberCommitEffects.js @@ -46,9 +46,6 @@ import {getPublicInstance} from './ReactFiberConfig'; import { captureCommitPhaseError, setIsRunningInsertionEffect, - getExecutionContext, - CommitContext, - NoContext, } from './ReactFiberWorkLoop'; import { NoFlags as NoHookEffect, @@ -81,8 +78,7 @@ function shouldProfile(current: Fiber): boolean { return ( enableProfilerTimer && enableProfilerCommitHooks && - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext + (current.mode & ProfileMode) !== NoMode ); } @@ -919,7 +915,7 @@ export function commitProfilerUpdate( commitTime: number, effectDuration: number, ) { - if (enableProfilerTimer && getExecutionContext() & CommitContext) { + if (enableProfilerTimer) { try { if (__DEV__) { runWithFiberInDEV( diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index bba93bbc0da2e..bf5b9c64030ea 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -145,9 +145,6 @@ import { addMarkerProgressCallbackToPendingTransition, addMarkerIncompleteCallbackToPendingTransition, addMarkerCompleteCallbackToPendingTransition, - getExecutionContext, - CommitContext, - NoContext, setIsRunningInsertionEffect, } from './ReactFiberWorkLoop'; import { @@ -233,8 +230,7 @@ function shouldProfile(current: Fiber): boolean { return ( enableProfilerTimer && enableProfilerCommitHooks && - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext + (current.mode & ProfileMode) !== NoMode ); } @@ -2817,11 +2813,7 @@ function commitPassiveMountOnFiber( // Only Profilers with work in their subtree will have a Passive effect scheduled. if (flags & Passive) { - if ( - enableProfilerTimer && - enableProfilerCommitHooks && - getExecutionContext() & CommitContext - ) { + if (enableProfilerTimer && enableProfilerCommitHooks) { const {passiveEffectDuration} = finishedWork.stateNode; commitProfilerPostCommit( From a99d8e8d97055127a8ad7b01835d2660154689ed Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:56:24 -0400 Subject: [PATCH 157/426] [compiler][eslint] Report bailout diagnostics with correct column # (#30977) Compiler bailout diagnostics should now highlight only the first line of the source location span. (Resubmission of #30423 which was reverted due to invalid column number.) --- .../src/rules/ReactCompilerRule.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts index f95eaaae007ed..b9a1ffa440c49 100644 --- a/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts +++ b/compiler/packages/eslint-plugin-react-compiler/src/rules/ReactCompilerRule.ts @@ -166,9 +166,33 @@ const rule: Rule.RuleModule = { detail.loc != null && typeof detail.loc !== 'symbol' ? ` (@:${detail.loc.start.line}:${detail.loc.start.column})` : ''; + /** + * Report bailouts with a smaller span (just the first line). + * Compiler bailout lints only serve to flag that a react function + * has not been optimized by the compiler for codebases which depend + * on compiler memo heavily for perf. These lints are also often not + * actionable. + */ + let endLoc; + if (event.fnLoc.end.line === event.fnLoc.start.line) { + endLoc = event.fnLoc.end; + } else { + endLoc = { + line: event.fnLoc.start.line, + // Babel loc line numbers are 1-indexed + column: sourceCode.split( + /\r?\n|\r|\n/g, + event.fnLoc.start.line, + )[event.fnLoc.start.line - 1].length, + }; + } + const firstLineLoc = { + start: event.fnLoc.start, + end: endLoc, + }; context.report({ message: `[ReactCompilerBailout] ${detail.reason}${locStr}`, - loc: event.fnLoc, + loc: firstLineLoc, suggest, }); } From 7b56a542987890f618eeda4e4906fbf1f1df2213 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Tue, 17 Sep 2024 11:05:59 -0700 Subject: [PATCH 158/426] [compiler][playground] create playground API in pipeline, and allow spaces in pass names Summary: 1. Minor refactor to provide a stable API for calling the compiler from the playground 2. Allows spaces in pass names without breaking the appearance of the playground by replacing spaces with   in pass tabs ghstack-source-id: 12a43ad86c16c0e21f3e6b4086d531cdefd893eb Pull Request resolved: https://github.com/facebook/react/pull/30988 --- .../apps/playground/components/Editor/EditorImpl.tsx | 12 +++--------- compiler/apps/playground/components/TabbedWindow.tsx | 7 +++++-- .../src/Entrypoint/Pipeline.ts | 11 +++++++++++ .../babel-plugin-react-compiler/src/index.ts | 1 + 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index ab85beebd5fca..5e3f3276b003f 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {parse as babelParse, ParserPlugin} from '@babel/parser'; +import {parse as babelParse} from '@babel/parser'; import * as HermesParser from 'hermes-parser'; import traverse, {NodePath} from '@babel/traverse'; import * as t from '@babel/types'; @@ -15,10 +15,8 @@ import { Effect, ErrorSeverity, parseConfigPragma, - printHIR, - printReactiveFunction, - run, ValueKind, + runPlayground, type Hook, } from 'babel-plugin-react-compiler/src'; import {type ReactFunctionType} from 'babel-plugin-react-compiler/src/HIR/Environment'; @@ -214,17 +212,13 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { for (const fn of parseFunctions(source, language)) { const id = withIdentifier(getFunctionIdentifier(fn)); - for (const result of run( + for (const result of runPlayground( fn, { ...config, customHooks: new Map([...COMMON_HOOKS]), }, getReactFunctionType(id), - '_c', - null, - null, - null, )) { const fnName = id.name; switch (result.kind) { diff --git a/compiler/apps/playground/components/TabbedWindow.tsx b/compiler/apps/playground/components/TabbedWindow.tsx index 1537a2817e1e0..4b01056f25bb7 100644 --- a/compiler/apps/playground/components/TabbedWindow.tsx +++ b/compiler/apps/playground/components/TabbedWindow.tsx @@ -69,6 +69,9 @@ function TabbedWindowItem({ setTabsOpen(nextState); }, [tabsOpen, name, setTabsOpen]); + // Replace spaces with non-breaking spaces + const displayName = name.replace(/ /g, '\u00A0'); + return (
{isShow ? ( @@ -80,7 +83,7 @@ function TabbedWindowItem({ className={`p-4 duration-150 ease-in border-b cursor-pointer border-grey-200 ${ hasChanged ? 'font-bold' : 'font-light' } text-secondary hover:text-link`}> - - {name} + - {displayName} {tabs.get(name) ??
No output for {name}
} @@ -94,7 +97,7 @@ function TabbedWindowItem({ className={`flex-grow-0 w-5 transition-colors duration-150 ease-in ${ hasChanged ? 'font-bold' : 'font-light' } text-secondary hover:text-link`}> - {name} + {displayName}
)} diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index aef18c90c2e5e..f87d371bed6a3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -554,3 +554,14 @@ export function log(value: CompilerPipelineValue): CompilerPipelineValue { } return value; } + +export function* runPlayground( + func: NodePath< + t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression + >, + config: EnvironmentConfig, + fnType: ReactFunctionType, +): Generator { + const ast = yield* run(func, config, fnType, '_c', null, null, null); + return ast; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/index.ts b/compiler/packages/babel-plugin-react-compiler/src/index.ts index aac65331a0ff2..256da2e5ed5c6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/index.ts @@ -18,6 +18,7 @@ export { compileProgram, parsePluginOptions, run, + runPlayground, OPT_OUT_DIRECTIVES, type CompilerPipelineValue, type PluginOptions, From 4549be0f846e7df5a4eaabf06369d93bd120271e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 17 Sep 2024 15:12:16 -0400 Subject: [PATCH 159/426] [Fiber] Optimize enableProfilerCommitHooks by Collecting Elapsed Effect Duration in Module Scope (#30981) Stacked on #30979. The problem with the previous approach is that it recursively walked the tree up to propagate the resulting time from recording a layout effect. Instead, we keep a running count of the effect duration on the module scope. Then we reset it when entering a nested Profiler and then we add its elapsed count when we exit the Profiler. This also fixes a bug where we weren't previously including unmount times for some detached trees since they couldn't bubble up to find the profiler. --- .../src/ReactFiberBeginWork.js | 8 +- .../src/ReactFiberCommitEffects.js | 71 ++- .../src/ReactFiberCommitWork.js | 428 +++++++----------- .../react-reconciler/src/ReactFiberRoot.js | 4 +- .../src/ReactInternalTypes.js | 7 +- .../src/ReactProfilerTimer.js | 117 ++--- .../__tests__/ReactProfiler-test.internal.js | 12 +- 7 files changed, 272 insertions(+), 375 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 398dd8372597a..f4ce6e849b25e 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -1033,8 +1033,8 @@ function updateProfiler( // Reset effect durations for the next eventual effect phase. // These are reset during render to allow the DevTools commit hook a chance to read them, const stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + stateNode.effectDuration = -0; + stateNode.passiveEffectDuration = -0; } } const nextProps = workInProgress.pendingProps; @@ -3711,8 +3711,8 @@ function attemptEarlyBailoutIfNoScheduledUpdate( // Reset effect durations for the next eventual effect phase. // These are reset during render to allow the DevTools commit hook a chance to read them, const stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + stateNode.effectDuration = -0; + stateNode.passiveEffectDuration = -0; } } break; diff --git a/packages/react-reconciler/src/ReactFiberCommitEffects.js b/packages/react-reconciler/src/ReactFiberCommitEffects.js index dde2479ba8638..8b1d4ceb6f9bb 100644 --- a/packages/react-reconciler/src/ReactFiberCommitEffects.js +++ b/packages/react-reconciler/src/ReactFiberCommitEffects.js @@ -31,10 +31,8 @@ import {NoFlags} from './ReactFiberFlags'; import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber'; import {resolveClassComponentProps} from './ReactFiberClassComponent'; import { - recordLayoutEffectDuration, - startLayoutEffectTimer, - recordPassiveEffectDuration, - startPassiveEffectTimer, + recordEffectDuration, + startEffectTimer, isCurrentUpdateNested, } from './ReactProfilerTimer'; import {NoMode, ProfileMode} from './ReactTypeOfMode'; @@ -91,14 +89,41 @@ export function commitHookLayoutEffects( // e.g. a destroy function in one component should never override a ref set // by a create function in another component during the same commit. if (shouldProfile(finishedWork)) { - startLayoutEffectTimer(); + startEffectTimer(); commitHookEffectListMount(hookFlags, finishedWork); - recordLayoutEffectDuration(finishedWork); + recordEffectDuration(finishedWork); } else { commitHookEffectListMount(hookFlags, finishedWork); } } +export function commitHookLayoutUnmountEffects( + finishedWork: Fiber, + nearestMountedAncestor: null | Fiber, + hookFlags: HookFlags, +) { + // Layout effects are destroyed during the mutation phase so that all + // destroy functions for all fibers are called before any create functions. + // This prevents sibling component effects from interfering with each other, + // e.g. a destroy function in one component should never override a ref set + // by a create function in another component during the same commit. + if (shouldProfile(finishedWork)) { + startEffectTimer(); + commitHookEffectListUnmount( + hookFlags, + finishedWork, + nearestMountedAncestor, + ); + recordEffectDuration(finishedWork); + } else { + commitHookEffectListUnmount( + hookFlags, + finishedWork, + nearestMountedAncestor, + ); + } +} + export function commitHookEffectListMount( flags: HookFlags, finishedWork: Fiber, @@ -265,9 +290,9 @@ export function commitHookPassiveMountEffects( hookFlags: HookFlags, ) { if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); + startEffectTimer(); commitHookEffectListMount(hookFlags, finishedWork); - recordPassiveEffectDuration(finishedWork); + recordEffectDuration(finishedWork); } else { commitHookEffectListMount(hookFlags, finishedWork); } @@ -279,13 +304,13 @@ export function commitHookPassiveUnmountEffects( hookFlags: HookFlags, ) { if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); + startEffectTimer(); commitHookEffectListUnmount( hookFlags, finishedWork, nearestMountedAncestor, ); - recordPassiveEffectDuration(finishedWork); + recordEffectDuration(finishedWork); } else { commitHookEffectListUnmount( hookFlags, @@ -333,7 +358,7 @@ export function commitClassLayoutLifecycles( } } if (shouldProfile(finishedWork)) { - startLayoutEffectTimer(); + startEffectTimer(); if (__DEV__) { runWithFiberInDEV( finishedWork, @@ -348,7 +373,7 @@ export function commitClassLayoutLifecycles( captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - recordLayoutEffectDuration(finishedWork); + recordEffectDuration(finishedWork); } else { if (__DEV__) { runWithFiberInDEV( @@ -404,7 +429,7 @@ export function commitClassLayoutLifecycles( } } if (shouldProfile(finishedWork)) { - startLayoutEffectTimer(); + startEffectTimer(); if (__DEV__) { runWithFiberInDEV( finishedWork, @@ -426,7 +451,7 @@ export function commitClassLayoutLifecycles( captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - recordLayoutEffectDuration(finishedWork); + recordEffectDuration(finishedWork); } else { if (__DEV__) { runWithFiberInDEV( @@ -679,7 +704,7 @@ export function safelyCallComponentWillUnmount( ); instance.state = current.memoizedState; if (shouldProfile(current)) { - startLayoutEffectTimer(); + startEffectTimer(); if (__DEV__) { runWithFiberInDEV( current, @@ -695,7 +720,7 @@ export function safelyCallComponentWillUnmount( captureCommitPhaseError(current, nearestMountedAncestor, error); } } - recordLayoutEffectDuration(current); + recordEffectDuration(current); } else { if (__DEV__) { runWithFiberInDEV( @@ -736,10 +761,10 @@ function commitAttachRef(finishedWork: Fiber) { if (typeof ref === 'function') { if (shouldProfile(finishedWork)) { try { - startLayoutEffectTimer(); + startEffectTimer(); finishedWork.refCleanup = ref(instanceToUse); } finally { - recordLayoutEffectDuration(finishedWork); + recordEffectDuration(finishedWork); } } else { finishedWork.refCleanup = ref(instanceToUse); @@ -793,14 +818,14 @@ export function safelyDetachRef( try { if (shouldProfile(current)) { try { - startLayoutEffectTimer(); + startEffectTimer(); if (__DEV__) { runWithFiberInDEV(current, refCleanup); } else { refCleanup(); } } finally { - recordLayoutEffectDuration(current); + recordEffectDuration(current); } } else { if (__DEV__) { @@ -823,14 +848,14 @@ export function safelyDetachRef( try { if (shouldProfile(current)) { try { - startLayoutEffectTimer(); + startEffectTimer(); if (__DEV__) { (runWithFiberInDEV(current, ref, null): void); } else { ref(null); } } finally { - recordLayoutEffectDuration(current); + recordEffectDuration(current); } } else { if (__DEV__) { @@ -849,7 +874,7 @@ export function safelyDetachRef( } } -export function safelyCallDestroy( +function safelyCallDestroy( current: Fiber, nearestMountedAncestor: Fiber | null, destroy: () => void, diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index bf5b9c64030ea..a0558ea549f76 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -44,7 +44,6 @@ import { enablePersistedModeClonedFlag, enableProfilerTimer, enableProfilerCommitHooks, - enableSchedulingProfiler, enableSuspenseCallback, enableScopeAPI, enableUpdaterTracking, @@ -101,9 +100,10 @@ import { } from './ReactFiberFlags'; import { getCommitTime, - recordLayoutEffectDuration, - startLayoutEffectTimer, getCompleteTime, + pushNestedEffectDurations, + popNestedEffectDurations, + bubbleNestedEffectDurations, } from './ReactProfilerTimer'; import {logComponentRender} from './ReactFiberPerformanceTrack'; import {ConcurrentMode, NoMode, ProfileMode} from './ReactTypeOfMode'; @@ -145,22 +145,15 @@ import { addMarkerProgressCallbackToPendingTransition, addMarkerIncompleteCallbackToPendingTransition, addMarkerCompleteCallbackToPendingTransition, - setIsRunningInsertionEffect, } from './ReactFiberWorkLoop'; import { - NoFlags as NoHookEffect, HasEffect as HookHasEffect, Layout as HookLayout, Insertion as HookInsertion, Passive as HookPassive, } from './ReactHookEffectTags'; import {doesFiberContain} from './ReactFiberTreeReflection'; -import { - isDevToolsPresent, - markComponentLayoutEffectUnmountStarted, - markComponentLayoutEffectUnmountStopped, - onCommitUnmount, -} from './ReactFiberDevToolsHook'; +import {isDevToolsPresent, onCommitUnmount} from './ReactFiberDevToolsHook'; import {releaseCache, retainCache} from './ReactFiberCacheComponent'; import {clearTransitionsForLanes} from './ReactFiberLane'; import { @@ -176,6 +169,7 @@ import {scheduleUpdateOnFiber} from './ReactFiberWorkLoop'; import {enqueueConcurrentRenderForLane} from './ReactFiberConcurrentUpdates'; import { commitHookLayoutEffects, + commitHookLayoutUnmountEffects, commitHookEffectListMount, commitHookEffectListUnmount, commitHookPassiveMountEffects, @@ -188,7 +182,6 @@ import { safelyCallComponentWillUnmount, safelyAttachRef, safelyDetachRef, - safelyCallDestroy, commitProfilerUpdate, commitProfilerPostCommit, commitRootCallbacks, @@ -226,14 +219,6 @@ let nextEffect: Fiber | null = null; let inProgressLanes: Lanes | null = null; let inProgressRoot: FiberRoot | null = null; -function shouldProfile(current: Fiber): boolean { - return ( - enableProfilerTimer && - enableProfilerCommitHooks && - (current.mode & ProfileMode) !== NoMode - ); -} - let focusedInstanceHandle: null | Fiber = null; let shouldFireAfterActiveInstanceBlur: boolean = false; @@ -434,6 +419,7 @@ function commitLayoutEffectOnFiber( break; } case HostRoot: { + const prevEffectDuration = pushNestedEffectDurations(); recursivelyTraverseLayoutEffects( finishedRoot, finishedWork, @@ -442,6 +428,10 @@ function commitLayoutEffectOnFiber( if (flags & Callback) { commitRootCallbacks(finishedWork); } + if (enableProfilerTimer && enableProfilerCommitHooks) { + finishedRoot.effectDuration += + popNestedEffectDurations(prevEffectDuration); + } break; } case HostHoistable: { @@ -481,39 +471,38 @@ function commitLayoutEffectOnFiber( break; } case Profiler: { - recursivelyTraverseLayoutEffects( - finishedRoot, - finishedWork, - committedLanes, - ); // TODO: Should this fire inside an offscreen tree? Or should it wait to // fire when the tree becomes visible again. if (flags & Update) { - const {effectDuration} = finishedWork.stateNode; + const prevEffectDuration = pushNestedEffectDurations(); + + recursivelyTraverseLayoutEffects( + finishedRoot, + finishedWork, + committedLanes, + ); + + const profilerInstance = finishedWork.stateNode; + + if (enableProfilerTimer && enableProfilerCommitHooks) { + // Propagate layout effect durations to the next nearest Profiler ancestor. + // Do not reset these values until the next render so DevTools has a chance to read them first. + profilerInstance.effectDuration += + bubbleNestedEffectDurations(prevEffectDuration); + } commitProfilerUpdate( finishedWork, current, getCommitTime(), - effectDuration, + profilerInstance.effectDuration, + ); + } else { + recursivelyTraverseLayoutEffects( + finishedRoot, + finishedWork, + committedLanes, ); - - // Propagate layout effect durations to the next nearest Profiler ancestor. - // Do not reset these values until the next render so DevTools has a chance to read them first. - let parentFiber = finishedWork.return; - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - const root = parentFiber.stateNode; - root.effectDuration += effectDuration; - break outer; - case Profiler: - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; - break outer; - } - parentFiber = parentFiber.return; - } } break; } @@ -1262,132 +1251,24 @@ function commitDeletionEffectsOnFiber( case ForwardRef: case MemoComponent: case SimpleMemoComponent: { - if (enableHiddenSubtreeInsertionEffectCleanup) { - // When deleting a fiber, we may need to destroy insertion or layout effects. - // Insertion effects are not destroyed on hidden, only when destroyed, so now - // we need to destroy them. Layout effects are destroyed when hidden, so - // we only need to destroy them if the tree is visible. - const updateQueue: FunctionComponentUpdateQueue | null = - (deletedFiber.updateQueue: any); - if (updateQueue !== null) { - const lastEffect = updateQueue.lastEffect; - if (lastEffect !== null) { - const firstEffect = lastEffect.next; - - let effect = firstEffect; - do { - const tag = effect.tag; - const inst = effect.inst; - const destroy = inst.destroy; - if (destroy !== undefined) { - if ((tag & HookInsertion) !== NoHookEffect) { - // TODO: add insertion effect marks and profiling. - if (__DEV__) { - setIsRunningInsertionEffect(true); - } - - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy, - ); - - if (__DEV__) { - setIsRunningInsertionEffect(false); - } - } else if ( - !offscreenSubtreeWasHidden && - (tag & HookLayout) !== NoHookEffect - ) { - // Offscreen fibers already unmounted their layout effects. - // We only need to destroy layout effects for visible trees. - if (enableSchedulingProfiler) { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } - - if (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy, - ); - recordLayoutEffectDuration(deletedFiber); - } else { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy, - ); - } - - if (enableSchedulingProfiler) { - markComponentLayoutEffectUnmountStopped(); - } - } - } - effect = effect.next; - } while (effect !== firstEffect); - } - } - } else if (!offscreenSubtreeWasHidden) { - const updateQueue: FunctionComponentUpdateQueue | null = - (deletedFiber.updateQueue: any); - if (updateQueue !== null) { - const lastEffect = updateQueue.lastEffect; - if (lastEffect !== null) { - const firstEffect = lastEffect.next; - - let effect = firstEffect; - do { - const tag = effect.tag; - const inst = effect.inst; - const destroy = inst.destroy; - if (destroy !== undefined) { - if ((tag & HookInsertion) !== NoHookEffect) { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy, - ); - } else if ((tag & HookLayout) !== NoHookEffect) { - if (enableSchedulingProfiler) { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } - - if (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy, - ); - recordLayoutEffectDuration(deletedFiber); - } else { - inst.destroy = undefined; - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy, - ); - } - - if (enableSchedulingProfiler) { - markComponentLayoutEffectUnmountStopped(); - } - } - } - effect = effect.next; - } while (effect !== firstEffect); - } - } + if ( + enableHiddenSubtreeInsertionEffectCleanup || + !offscreenSubtreeWasHidden + ) { + // TODO: Use a commitHookInsertionUnmountEffects wrapper to record timings. + commitHookEffectListUnmount( + HookInsertion, + deletedFiber, + nearestMountedAncestor, + ); + } + if (!offscreenSubtreeWasHidden) { + commitHookLayoutUnmountEffects( + deletedFiber, + nearestMountedAncestor, + HookLayout, + ); } - recursivelyTraverseDeletionEffects( finishedRoot, nearestMountedAncestor, @@ -1709,27 +1590,13 @@ function commitMutationEffectsOnFiber( finishedWork, finishedWork.return, ); + // TODO: Use a commitHookInsertionUnmountEffects wrapper to record timings. commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork); - // Layout effects are destroyed during the mutation phase so that all - // destroy functions for all fibers are called before any create functions. - // This prevents sibling component effects from interfering with each other, - // e.g. a destroy function in one component should never override a ref set - // by a create function in another component during the same commit. - if (shouldProfile(finishedWork)) { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - HookLayout | HookHasEffect, - finishedWork, - finishedWork.return, - ); - recordLayoutEffectDuration(finishedWork); - } else { - commitHookEffectListUnmount( - HookLayout | HookHasEffect, - finishedWork, - finishedWork.return, - ); - } + commitHookLayoutUnmountEffects( + finishedWork, + finishedWork.return, + HookLayout | HookHasEffect, + ); } return; } @@ -1917,6 +1784,8 @@ function commitMutationEffectsOnFiber( return; } case HostRoot: { + const prevEffectDuration = pushNestedEffectDurations(); + if (supportsResources) { prepareToCommitHoistables(); @@ -1960,6 +1829,10 @@ function commitMutationEffectsOnFiber( recursivelyResetForms(finishedWork); } + if (enableProfilerTimer && enableProfilerCommitHooks) { + root.effectDuration += popNestedEffectDurations(prevEffectDuration); + } + return; } case HostPortal: { @@ -1987,6 +1860,21 @@ function commitMutationEffectsOnFiber( } return; } + case Profiler: { + const prevEffectDuration = pushNestedEffectDurations(); + + recursivelyTraverseMutationEffects(root, finishedWork, lanes); + commitReconciliationEffects(finishedWork); + + if (enableProfilerTimer && enableProfilerCommitHooks) { + const profilerInstance = finishedWork.stateNode; + // Propagate layout effect durations to the next nearest Profiler ancestor. + // Do not reset these values until the next render so DevTools has a chance to read them first. + profilerInstance.effectDuration += + bubbleNestedEffectDurations(prevEffectDuration); + } + return; + } case SuspenseComponent: { recursivelyTraverseMutationEffects(root, finishedWork, lanes); commitReconciliationEffects(finishedWork); @@ -2247,25 +2135,11 @@ export function disappearLayoutEffects(finishedWork: Fiber) { case MemoComponent: case SimpleMemoComponent: { // TODO (Offscreen) Check: flags & LayoutStatic - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - HookLayout, - finishedWork, - finishedWork.return, - ); - } finally { - recordLayoutEffectDuration(finishedWork); - } - } else { - commitHookEffectListUnmount( - HookLayout, - finishedWork, - finishedWork.return, - ); - } - + commitHookLayoutUnmountEffects( + finishedWork, + finishedWork.return, + HookLayout, + ); recursivelyTraverseDisappearLayoutEffects(finishedWork); break; } @@ -2395,38 +2269,37 @@ export function reappearLayoutEffects( break; } case Profiler: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects, - ); // TODO: Figure out how Profiler updates should work with Offscreen if (includeWorkInProgressEffects && flags & Update) { - const {effectDuration} = finishedWork.stateNode; + const prevEffectDuration = pushNestedEffectDurations(); + + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects, + ); + + const profilerInstance = finishedWork.stateNode; + + if (enableProfilerTimer && enableProfilerCommitHooks) { + // Propagate layout effect durations to the next nearest Profiler ancestor. + // Do not reset these values until the next render so DevTools has a chance to read them first. + profilerInstance.effectDuration += + bubbleNestedEffectDurations(prevEffectDuration); + } commitProfilerUpdate( finishedWork, current, getCommitTime(), - effectDuration, + profilerInstance.effectDuration, + ); + } else { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects, ); - - // Propagate layout effect durations to the next nearest Profiler ancestor. - // Do not reset these values until the next render so DevTools has a chance to read them first. - let parentFiber = finishedWork.return; - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - const root = parentFiber.stateNode; - root.effectDuration += effectDuration; - break outer; - case Profiler: - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; - break outer; - } - parentFiber = parentFiber.return; - } } break; } @@ -2745,6 +2618,7 @@ function commitPassiveMountOnFiber( break; } case HostRoot: { + const prevEffectDuration = pushNestedEffectDurations(); recursivelyTraversePassiveMountEffects( finishedRoot, finishedWork, @@ -2800,48 +2674,50 @@ function commitPassiveMountOnFiber( clearTransitionsForLanes(finishedRoot, committedLanes); } } + if (enableProfilerTimer && enableProfilerCommitHooks) { + finishedRoot.passiveEffectDuration += + popNestedEffectDurations(prevEffectDuration); + } break; } case Profiler: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - endTime, - ); - // Only Profilers with work in their subtree will have a Passive effect scheduled. if (flags & Passive) { - if (enableProfilerTimer && enableProfilerCommitHooks) { - const {passiveEffectDuration} = finishedWork.stateNode; + const prevEffectDuration = pushNestedEffectDurations(); - commitProfilerPostCommit( - finishedWork, - finishedWork.alternate, - // This value will still reflect the previous commit phase. - // It does not get reset until the start of the next commit phase. - getCommitTime(), - passiveEffectDuration, - ); + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + endTime, + ); + + const profilerInstance = finishedWork.stateNode; + if (enableProfilerTimer && enableProfilerCommitHooks) { // Bubble times to the next nearest ancestor Profiler. // After we process that Profiler, we'll bubble further up. - let parentFiber = finishedWork.return; - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - const root = parentFiber.stateNode; - root.passiveEffectDuration += passiveEffectDuration; - break outer; - case Profiler: - const parentStateNode = parentFiber.stateNode; - parentStateNode.passiveEffectDuration += passiveEffectDuration; - break outer; - } - parentFiber = parentFiber.return; - } + profilerInstance.passiveEffectDuration += + bubbleNestedEffectDurations(prevEffectDuration); } + + commitProfilerPostCommit( + finishedWork, + finishedWork.alternate, + // This value will still reflect the previous commit phase. + // It does not get reset until the start of the next commit phase. + getCommitTime(), + profilerInstance.passiveEffectDuration, + ); + } else { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + endTime, + ); } break; } @@ -3427,6 +3303,30 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { } break; } + case HostRoot: { + const prevEffectDuration = pushNestedEffectDurations(); + recursivelyTraversePassiveUnmountEffects(finishedWork); + if (enableProfilerTimer && enableProfilerCommitHooks) { + const finishedRoot: FiberRoot = finishedWork.stateNode; + finishedRoot.passiveEffectDuration += + popNestedEffectDurations(prevEffectDuration); + } + break; + } + case Profiler: { + const prevEffectDuration = pushNestedEffectDurations(); + + recursivelyTraversePassiveUnmountEffects(finishedWork); + + if (enableProfilerTimer && enableProfilerCommitHooks) { + const profilerInstance = finishedWork.stateNode; + // Propagate layout effect durations to the next nearest Profiler ancestor. + // Do not reset these values until the next render so DevTools has a chance to read them first. + profilerInstance.passiveEffectDuration += + bubbleNestedEffectDurations(prevEffectDuration); + } + break; + } case OffscreenComponent: { const instance: OffscreenInstance = finishedWork.stateNode; const nextState: OffscreenState | null = finishedWork.memoizedState; diff --git a/packages/react-reconciler/src/ReactFiberRoot.js b/packages/react-reconciler/src/ReactFiberRoot.js index f62a5d7158db1..176c3846d1336 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.js +++ b/packages/react-reconciler/src/ReactFiberRoot.js @@ -112,8 +112,8 @@ function FiberRootNode( } if (enableProfilerTimer && enableProfilerCommitHooks) { - this.effectDuration = 0; - this.passiveEffectDuration = 0; + this.effectDuration = -0; + this.passiveEffectDuration = -0; } if (enableUpdaterTracking) { diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index d160aa0d228f5..1c98a9e9c7fbc 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -373,6 +373,11 @@ type TransitionTracingOnlyFiberRootProperties = { incompleteTransitions: Map, }; +type ProfilerCommitHooksOnlyFiberRootProperties = { + effectDuration: number, + passiveEffectDuration: number, +}; + // Exported FiberRoot type includes all properties, // To avoid requiring potentially error-prone :any casts throughout the project. // The types are defined separately within this file to ensure they stay in sync. @@ -381,7 +386,7 @@ export type FiberRoot = { ...SuspenseCallbackOnlyFiberRootProperties, ...UpdaterTrackingOnlyFiberRootProperties, ...TransitionTracingOnlyFiberRootProperties, - ... + ...ProfilerCommitHooksOnlyFiberRootProperties, }; type BasicStateAction = (S => S) | S; diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index bad2f60490d54..3cccc399327ba 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -14,7 +14,6 @@ import { enableProfilerNestedUpdatePhase, enableProfilerTimer, } from 'shared/ReactFeatureFlags'; -import {HostRoot, Profiler} from './ReactWorkTags'; // Intentionally not named imports because Rollup would use dynamic dispatch for // CommonJS interop named imports. @@ -35,11 +34,38 @@ export type ProfilerTimer = { ... }; -let completeTime: number = 0; -let commitTime: number = 0; -let layoutEffectStartTime: number = -1; -let profilerStartTime: number = -1; -let passiveEffectStartTime: number = -1; +let completeTime: number = -0; +let commitTime: number = -0; +let profilerStartTime: number = -1.1; +let profilerEffectDuration: number = -0; + +function pushNestedEffectDurations(): number { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return 0; + } + const prevEffectDuration = profilerEffectDuration; + profilerEffectDuration = 0; // Reset counter. + return prevEffectDuration; +} + +function popNestedEffectDurations(prevEffectDuration: number): number { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return 0; + } + const elapsedTime = profilerEffectDuration; + profilerEffectDuration = prevEffectDuration; + return elapsedTime; +} + +// Like pop but it also adds the current elapsed time to the parent scope. +function bubbleNestedEffectDurations(prevEffectDuration: number): number { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return 0; + } + const elapsedTime = profilerEffectDuration; + profilerEffectDuration += prevEffectDuration; + return elapsedTime; +} /** * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). @@ -153,83 +179,27 @@ function stopProfilerTimerIfRunningAndRecordIncompleteDuration( } } -function recordLayoutEffectDuration(fiber: Fiber): void { - if (!enableProfilerTimer || !enableProfilerCommitHooks) { - return; - } - - if (layoutEffectStartTime >= 0) { - const elapsedTime = now() - layoutEffectStartTime; - - layoutEffectStartTime = -1; - - // Store duration on the next nearest Profiler ancestor - // Or the root (for the DevTools Profiler to read) - let parentFiber = fiber.return; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - const root = parentFiber.stateNode; - root.effectDuration += elapsedTime; - return; - case Profiler: - const parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - return; - } - parentFiber = parentFiber.return; - } - } -} - -function recordPassiveEffectDuration(fiber: Fiber): void { +function recordEffectDuration(fiber: Fiber): void { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return; } - if (passiveEffectStartTime >= 0) { - const elapsedTime = now() - passiveEffectStartTime; + if (profilerStartTime >= 0) { + const elapsedTime = now() - profilerStartTime; - passiveEffectStartTime = -1; + profilerStartTime = -1; // Store duration on the next nearest Profiler ancestor // Or the root (for the DevTools Profiler to read) - let parentFiber = fiber.return; - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - const root = parentFiber.stateNode; - if (root !== null) { - root.passiveEffectDuration += elapsedTime; - } - return; - case Profiler: - const parentStateNode = parentFiber.stateNode; - if (parentStateNode !== null) { - // Detached fibers have their state node cleared out. - // In this case, the return pointer is also cleared out, - // so we won't be able to report the time spent in this Profiler's subtree. - parentStateNode.passiveEffectDuration += elapsedTime; - } - return; - } - parentFiber = parentFiber.return; - } - } -} - -function startLayoutEffectTimer(): void { - if (!enableProfilerTimer || !enableProfilerCommitHooks) { - return; + profilerEffectDuration += elapsedTime; } - layoutEffectStartTime = now(); } -function startPassiveEffectTimer(): void { +function startEffectTimer(): void { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return; } - passiveEffectStartTime = now(); + profilerStartTime = now(); } function transferActualDuration(fiber: Fiber): void { @@ -251,15 +221,16 @@ export { recordCommitTime, isCurrentUpdateNested, markNestedUpdateScheduled, - recordLayoutEffectDuration, - recordPassiveEffectDuration, + recordEffectDuration, resetNestedUpdateFlag, - startLayoutEffectTimer, - startPassiveEffectTimer, + startEffectTimer, startProfilerTimer, stopProfilerTimerIfRunning, stopProfilerTimerIfRunningAndRecordDuration, stopProfilerTimerIfRunningAndRecordIncompleteDuration, syncNestedUpdateFlag, transferActualDuration, + pushNestedEffectDurations, + popNestedEffectDurations, + bubbleNestedEffectDurations, }; diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index a19e9b1c6d161..0d7aead65f81d 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -1643,7 +1643,7 @@ describe(`onCommit`, () => { expect(call).toHaveLength(4); expect(call[0]).toBe('root-update'); expect(call[1]).toBe('update'); - expect(call[2]).toBe(1100); // durations + expect(call[2]).toBe(11100); // durations expect(call[3]).toBe(1124); // commit start time (before mutations or effects) }); @@ -1952,11 +1952,7 @@ describe(`onPostCommit`, () => { expect(call).toHaveLength(4); expect(call[0]).toBe('unmount-test'); expect(call[1]).toBe('update'); - // TODO (bvaughn) The duration reported below should be 10100, but is 0 - // by the time the passive effect is flushed its parent Fiber pointer is gone. - // If we refactor to preserve the unmounted Fiber tree we could fix this. - // The current implementation would require too much extra overhead to track this. - expect(call[2]).toBe(0); // durations + expect(call[2]).toBe(10100); // durations expect(call[3]).toBe(12030); // commit start time (before mutations or effects) }); @@ -2085,7 +2081,7 @@ describe(`onPostCommit`, () => { expect(call).toHaveLength(4); expect(call[0]).toBe('root-update'); expect(call[1]).toBe('update'); - expect(call[2]).toBe(1100); // durations + expect(call[2]).toBe(11100); // durations expect(call[3]).toBe(1124); // commit start time (before mutations or effects) }); @@ -2300,7 +2296,7 @@ describe(`onPostCommit`, () => { expect(call).toHaveLength(4); expect(call[0]).toBe('root'); expect(call[1]).toBe('update'); - expect(call[2]).toBe(100000000); // durations + expect(call[2]).toBe(100001000); // durations // The commit time varies because the above duration time varies expect(call[3]).toBe(11221221); // commit start time (before mutations or effects) }); From 15da9174518f18f82869767ebe2a21be2fc8bd90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 17 Sep 2024 15:25:00 -0400 Subject: [PATCH 160/426] Don't read currentTransition back from internals (#30991) This code is weird. It reads back the transition that it just set from the shared internals. It's almost like it expects it to be a getter or something. This avoids that and makes it consistent with what ReactFiberHooks already does. --- packages/react/src/ReactStartTransition.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/react/src/ReactStartTransition.js b/packages/react/src/ReactStartTransition.js index 6bae8947e1cea..a9b30c424a07f 100644 --- a/packages/react/src/ReactStartTransition.js +++ b/packages/react/src/ReactStartTransition.js @@ -23,20 +23,17 @@ export function startTransition( options?: StartTransitionOptions, ) { const prevTransition = ReactSharedInternals.T; - const transition: BatchConfigTransition = {}; - ReactSharedInternals.T = transition; - const currentTransition = ReactSharedInternals.T; + const currentTransition: BatchConfigTransition = {}; + ReactSharedInternals.T = currentTransition; if (__DEV__) { - ReactSharedInternals.T._updatedFibers = new Set(); + currentTransition._updatedFibers = new Set(); } if (enableTransitionTracing) { if (options !== undefined && options.name !== undefined) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - ReactSharedInternals.T.name = options.name; - // $FlowFixMe[incompatible-use] found when upgrading Flow - ReactSharedInternals.T.startTime = -1; + currentTransition.name = options.name; + currentTransition.startTime = -1; } } @@ -45,7 +42,7 @@ export function startTransition( const returnValue = scope(); const onStartTransitionFinish = ReactSharedInternals.S; if (onStartTransitionFinish !== null) { - onStartTransitionFinish(transition, returnValue); + onStartTransitionFinish(currentTransition, returnValue); } if ( typeof returnValue === 'object' && From e1c20902c39d1dfe2649185622f2f21b526e2be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 17 Sep 2024 16:14:57 -0400 Subject: [PATCH 161/426] [Fiber] Log Component Effects to Performance Track (#30983) Stacked on #30981. Same as #30967 but for effects. This logs a tree of components using `performance.measure()`. In addition to the previous render phase this logs one tree for each commit phase: - Mutation Phase - Layout Effect - Passive Unmounts - Passive Mounts I currently skip the Before Mutation phase since the snapshots are so unusual it's not worth creating trees for those. The mechanism is that I reuse the timings we track for `enableProfilerCommitHooks`. I track first and last effect timestamp within each component subtree. Then on the way up do we log the entry. This means that we don't include overhead to find our way down to a component and that we don't need to add any additional overhead by reading timestamps. To ensure that the entries get ordered correctly we need to ensure that the start time of each parent is slightly before the inner one. --- .../src/ReactFiberCommitWork.js | 134 +++++++++++++++--- .../src/ReactFiberPerformanceTrack.js | 36 ++++- .../src/ReactProfilerTimer.js | 133 ++++++++--------- 3 files changed, 215 insertions(+), 88 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index a0558ea549f76..4c66470342c89 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -99,13 +99,21 @@ import { Cloned, } from './ReactFiberFlags'; import { - getCommitTime, - getCompleteTime, + commitTime, + completeTime, pushNestedEffectDurations, popNestedEffectDurations, bubbleNestedEffectDurations, + resetComponentEffectTimers, + pushComponentEffectStart, + popComponentEffectStart, + componentEffectStartTime, + componentEffectEndTime, } from './ReactProfilerTimer'; -import {logComponentRender} from './ReactFiberPerformanceTrack'; +import { + logComponentRender, + logComponentEffect, +} from './ReactFiberPerformanceTrack'; import {ConcurrentMode, NoMode, ProfileMode} from './ReactTypeOfMode'; import {deferHiddenCallbacks} from './ReactFiberClassUpdateQueue'; import { @@ -382,6 +390,8 @@ function commitLayoutEffectOnFiber( finishedWork: Fiber, committedLanes: Lanes, ): void { + const prevEffectStart = pushComponentEffectStart(); + // When updating this function, also update reappearLayoutEffects, which does // most of the same things when an offscreen tree goes from hidden -> visible. const flags = finishedWork.flags; @@ -494,7 +504,7 @@ function commitLayoutEffectOnFiber( commitProfilerUpdate( finishedWork, current, - getCommitTime(), + commitTime, profilerInstance.effectDuration, ); } else { @@ -585,6 +595,23 @@ function commitLayoutEffectOnFiber( break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + ); + } + + popComponentEffectStart(prevEffectStart); } function abortRootTransitions( @@ -1530,6 +1557,8 @@ export function commitMutationEffects( inProgressLanes = committedLanes; inProgressRoot = root; + resetComponentEffectTimers(); + commitMutationEffectsOnFiber(finishedWork, root, committedLanes); inProgressLanes = null; @@ -1570,6 +1599,8 @@ function commitMutationEffectsOnFiber( root: FiberRoot, lanes: Lanes, ) { + const prevEffectStart = pushComponentEffectStart(); + const current = finishedWork.alternate; const flags = finishedWork.flags; @@ -1598,7 +1629,7 @@ function commitMutationEffectsOnFiber( HookLayout | HookHasEffect, ); } - return; + break; } case ClassComponent: { recursivelyTraverseMutationEffects(root, finishedWork, lanes); @@ -1617,7 +1648,7 @@ function commitMutationEffectsOnFiber( deferHiddenCallbacks(updateQueue); } } - return; + break; } case HostHoistable: { if (supportsResources) { @@ -1693,7 +1724,7 @@ function commitMutationEffectsOnFiber( ); } } - return; + break; } // Fall through } @@ -1756,7 +1787,7 @@ function commitMutationEffectsOnFiber( } } } - return; + break; } case HostText: { recursivelyTraverseMutationEffects(root, finishedWork, lanes); @@ -1781,7 +1812,7 @@ function commitMutationEffectsOnFiber( commitHostTextUpdate(finishedWork, newText, oldText); } } - return; + break; } case HostRoot: { const prevEffectDuration = pushNestedEffectDurations(); @@ -1833,7 +1864,7 @@ function commitMutationEffectsOnFiber( root.effectDuration += popNestedEffectDurations(prevEffectDuration); } - return; + break; } case HostPortal: { if (supportsResources) { @@ -1858,7 +1889,7 @@ function commitMutationEffectsOnFiber( ); } } - return; + break; } case Profiler: { const prevEffectDuration = pushNestedEffectDurations(); @@ -1873,7 +1904,7 @@ function commitMutationEffectsOnFiber( profilerInstance.effectDuration += bubbleNestedEffectDurations(prevEffectDuration); } - return; + break; } case SuspenseComponent: { recursivelyTraverseMutationEffects(root, finishedWork, lanes); @@ -1925,7 +1956,7 @@ function commitMutationEffectsOnFiber( attachSuspenseRetryListeners(finishedWork, retryQueue); } } - return; + break; } case OffscreenComponent: { if (flags & Ref) { @@ -2018,7 +2049,7 @@ function commitMutationEffectsOnFiber( } } } - return; + break; } case SuspenseListComponent: { recursivelyTraverseMutationEffects(root, finishedWork, lanes); @@ -2032,7 +2063,7 @@ function commitMutationEffectsOnFiber( attachSuspenseRetryListeners(finishedWork, retryQueue); } } - return; + break; } case ScopeComponent: { if (enableScopeAPI) { @@ -2052,16 +2083,34 @@ function commitMutationEffectsOnFiber( prepareScopeUpdate(scopeInstance, finishedWork); } } - return; + break; } default: { recursivelyTraverseMutationEffects(root, finishedWork, lanes); commitReconciliationEffects(finishedWork); - return; + break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + ); + } + + popComponentEffectStart(prevEffectStart); } + function commitReconciliationEffects(finishedWork: Fiber) { // Placement effects (insertions, reorders) can be scheduled on any fiber // type. They needs to happen after the children effects have fired, but @@ -2106,6 +2155,8 @@ export function commitLayoutEffects( inProgressLanes = committedLanes; inProgressRoot = root; + resetComponentEffectTimers(); + const current = finishedWork.alternate; commitLayoutEffectOnFiber(root, current, finishedWork, committedLanes); @@ -2291,7 +2342,7 @@ export function reappearLayoutEffects( commitProfilerUpdate( finishedWork, current, - getCommitTime(), + commitTime, profilerInstance.effectDuration, ); } else { @@ -2515,14 +2566,14 @@ export function commitPassiveMountEffects( committedLanes: Lanes, committedTransitions: Array | null, ): void { + resetComponentEffectTimers(); + commitPassiveMountOnFiber( root, finishedWork, committedLanes, committedTransitions, - enableProfilerTimer && enableComponentPerformanceTrack - ? getCompleteTime() - : 0, + enableProfilerTimer && enableComponentPerformanceTrack ? completeTime : 0, ); } @@ -2577,6 +2628,8 @@ function commitPassiveMountOnFiber( committedTransitions: Array | null, endTime: number, // Profiling-only. The start time of the next Fiber or root completion. ): void { + const prevEffectStart = pushComponentEffectStart(); + // If this component rendered in Profiling mode (DEV or in Profiler component) then log its // render time. We do this after the fact in the passive effect to avoid the overhead of this // getting in the way of the render characteristics and avoid the overhead of unwinding @@ -2707,7 +2760,7 @@ function commitPassiveMountOnFiber( finishedWork.alternate, // This value will still reflect the previous commit phase. // It does not get reset until the start of the next commit phase. - getCommitTime(), + commitTime, profilerInstance.passiveEffectDuration, ); } else { @@ -2860,6 +2913,23 @@ function commitPassiveMountOnFiber( break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + ); + } + + popComponentEffectStart(prevEffectStart); } function recursivelyTraverseReconnectPassiveEffects( @@ -3131,6 +3201,7 @@ function commitAtomicPassiveEffects( } export function commitPassiveUnmountEffects(finishedWork: Fiber): void { + resetComponentEffectTimers(); commitPassiveUnmountOnFiber(finishedWork); } @@ -3289,6 +3360,8 @@ function recursivelyTraversePassiveUnmountEffects(parentFiber: Fiber): void { } function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { + const prevEffectStart = pushComponentEffectStart(); + switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: @@ -3358,6 +3431,23 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { break; } } + + if ( + enableProfilerTimer && + enableProfilerCommitHooks && + enableComponentPerformanceTrack && + (finishedWork.mode & ProfileMode) !== NoMode && + componentEffectStartTime >= 0 && + componentEffectEndTime >= 0 + ) { + logComponentEffect( + finishedWork, + componentEffectStartTime, + componentEffectEndTime, + ); + } + + popComponentEffectStart(prevEffectStart); } function recursivelyTraverseDisconnectPassiveEffects(parentFiber: Fiber): void { diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 2058a04e47454..9c6c7ff8a80d3 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -38,9 +38,24 @@ const reusableComponentOptions = { }, }; +const reusableComponentEffectDevToolDetails = { + dataType: 'track-entry', + color: 'secondary', + track: 'Blocking', // Lane + trackGroup: TRACK_GROUP, +}; +const reusableComponentEffectOptions = { + start: -0, + end: -0, + detail: { + devtools: reusableComponentEffectDevToolDetails, + }, +}; + export function setCurrentTrackFromLanes(lanes: number): void { - reusableComponentDevToolDetails.track = - getGroupNameOfHighestPriorityLane(lanes); + reusableComponentEffectDevToolDetails.track = + reusableComponentDevToolDetails.track = + getGroupNameOfHighestPriorityLane(lanes); } export function logComponentRender( @@ -59,3 +74,20 @@ export function logComponentRender( performance.measure(name, reusableComponentOptions); } } + +export function logComponentEffect( + fiber: Fiber, + startTime: number, + endTime: number, +): void { + const name = getComponentNameFromFiber(fiber); + if (name === null) { + // Skip + return; + } + if (supportsUserTiming) { + reusableComponentEffectOptions.start = startTime; + reusableComponentEffectOptions.end = endTime; + performance.measure(name, reusableComponentEffectOptions); + } +} diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index 3cccc399327ba..da450d7f28f52 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -21,25 +21,14 @@ import * as Scheduler from 'scheduler'; const {unstable_now: now} = Scheduler; -export type ProfilerTimer = { - getCommitTime(): number, - isCurrentUpdateNested(): boolean, - markNestedUpdateScheduled(): void, - recordCommitTime(): void, - startProfilerTimer(fiber: Fiber): void, - stopProfilerTimerIfRunning(fiber: Fiber): void, - stopProfilerTimerIfRunningAndRecordDuration(fiber: Fiber): void, - stopProfilerTimerIfRunningAndRecordIncompleteDuration(fiber: Fiber): void, - syncNestedUpdateFlag(): void, - ... -}; - -let completeTime: number = -0; -let commitTime: number = -0; -let profilerStartTime: number = -1.1; -let profilerEffectDuration: number = -0; - -function pushNestedEffectDurations(): number { +export let completeTime: number = -0; +export let commitTime: number = -0; +export let profilerStartTime: number = -1.1; +export let profilerEffectDuration: number = -0; +export let componentEffectStartTime: number = -1.1; +export let componentEffectEndTime: number = -1.1; + +export function pushNestedEffectDurations(): number { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return 0; } @@ -48,7 +37,7 @@ function pushNestedEffectDurations(): number { return prevEffectDuration; } -function popNestedEffectDurations(prevEffectDuration: number): number { +export function popNestedEffectDurations(prevEffectDuration: number): number { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return 0; } @@ -58,7 +47,9 @@ function popNestedEffectDurations(prevEffectDuration: number): number { } // Like pop but it also adds the current elapsed time to the parent scope. -function bubbleNestedEffectDurations(prevEffectDuration: number): number { +export function bubbleNestedEffectDurations( + prevEffectDuration: number, +): number { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return 0; } @@ -67,6 +58,39 @@ function bubbleNestedEffectDurations(prevEffectDuration: number): number { return elapsedTime; } +export function resetComponentEffectTimers(): void { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return; + } + componentEffectStartTime = -1.1; + componentEffectEndTime = -1.1; +} + +export function pushComponentEffectStart(): number { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return 0; + } + const prevEffectStart = componentEffectStartTime; + componentEffectStartTime = -1.1; // Track the next start. + return prevEffectStart; +} + +export function popComponentEffectStart(prevEffectStart: number): void { + if (!enableProfilerTimer || !enableProfilerCommitHooks) { + return; + } + if (prevEffectStart < 0) { + // If the parent component didn't have a start time, we use the start + // of the child as the parent's start time. We subtrack a minimal amount of + // time to ensure that the parent's start time is before the child to ensure + // that the performance tracks line up in the right order. + componentEffectStartTime -= 0.001; + } else { + // Otherwise, we restore the previous parent's start time. + componentEffectStartTime = prevEffectStart; + } +} + /** * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). * @@ -86,53 +110,45 @@ function bubbleNestedEffectDurations(prevEffectDuration: number): number { let currentUpdateIsNested: boolean = false; let nestedUpdateScheduled: boolean = false; -function isCurrentUpdateNested(): boolean { +export function isCurrentUpdateNested(): boolean { return currentUpdateIsNested; } -function markNestedUpdateScheduled(): void { +export function markNestedUpdateScheduled(): void { if (enableProfilerNestedUpdatePhase) { nestedUpdateScheduled = true; } } -function resetNestedUpdateFlag(): void { +export function resetNestedUpdateFlag(): void { if (enableProfilerNestedUpdatePhase) { currentUpdateIsNested = false; nestedUpdateScheduled = false; } } -function syncNestedUpdateFlag(): void { +export function syncNestedUpdateFlag(): void { if (enableProfilerNestedUpdatePhase) { currentUpdateIsNested = nestedUpdateScheduled; nestedUpdateScheduled = false; } } -function getCompleteTime(): number { - return completeTime; -} - -function recordCompleteTime(): void { +export function recordCompleteTime(): void { if (!enableProfilerTimer) { return; } completeTime = now(); } -function getCommitTime(): number { - return commitTime; -} - -function recordCommitTime(): void { +export function recordCommitTime(): void { if (!enableProfilerTimer) { return; } commitTime = now(); } -function startProfilerTimer(fiber: Fiber): void { +export function startProfilerTimer(fiber: Fiber): void { if (!enableProfilerTimer) { return; } @@ -144,14 +160,16 @@ function startProfilerTimer(fiber: Fiber): void { } } -function stopProfilerTimerIfRunning(fiber: Fiber): void { +export function stopProfilerTimerIfRunning(fiber: Fiber): void { if (!enableProfilerTimer) { return; } profilerStartTime = -1; } -function stopProfilerTimerIfRunningAndRecordDuration(fiber: Fiber): void { +export function stopProfilerTimerIfRunningAndRecordDuration( + fiber: Fiber, +): void { if (!enableProfilerTimer) { return; } @@ -164,7 +182,7 @@ function stopProfilerTimerIfRunningAndRecordDuration(fiber: Fiber): void { } } -function stopProfilerTimerIfRunningAndRecordIncompleteDuration( +export function stopProfilerTimerIfRunningAndRecordIncompleteDuration( fiber: Fiber, ): void { if (!enableProfilerTimer) { @@ -179,30 +197,38 @@ function stopProfilerTimerIfRunningAndRecordIncompleteDuration( } } -function recordEffectDuration(fiber: Fiber): void { +export function recordEffectDuration(fiber: Fiber): void { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return; } if (profilerStartTime >= 0) { - const elapsedTime = now() - profilerStartTime; + const endTime = now(); + const elapsedTime = endTime - profilerStartTime; profilerStartTime = -1; // Store duration on the next nearest Profiler ancestor // Or the root (for the DevTools Profiler to read) profilerEffectDuration += elapsedTime; + + // Keep track of the last end time of the effects. + componentEffectEndTime = endTime; } } -function startEffectTimer(): void { +export function startEffectTimer(): void { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return; } profilerStartTime = now(); + if (componentEffectStartTime < 0) { + // Keep track of the first time we start an effect as the component's effect start time. + componentEffectStartTime = profilerStartTime; + } } -function transferActualDuration(fiber: Fiber): void { +export function transferActualDuration(fiber: Fiber): void { // Transfer time spent rendering these children so we don't lose it // after we rerender. This is used as a helper in special cases // where we should count the work of multiple passes. @@ -213,24 +239,3 @@ function transferActualDuration(fiber: Fiber): void { child = child.sibling; } } - -export { - getCompleteTime, - recordCompleteTime, - getCommitTime, - recordCommitTime, - isCurrentUpdateNested, - markNestedUpdateScheduled, - recordEffectDuration, - resetNestedUpdateFlag, - startEffectTimer, - startProfilerTimer, - stopProfilerTimerIfRunning, - stopProfilerTimerIfRunningAndRecordDuration, - stopProfilerTimerIfRunningAndRecordIncompleteDuration, - syncNestedUpdateFlag, - transferActualDuration, - pushNestedEffectDurations, - popNestedEffectDurations, - bubbleNestedEffectDurations, -}; From 8dfbd16fce9077ab4e5fe85a7b86fa7c97a5ae04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 17 Sep 2024 16:36:10 -0400 Subject: [PATCH 162/426] [Fiber] Color Performance Track Entries by Self Time (#30984) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacked on #30983. This colors each component entry by its self time from light to dark depending on how long it took. If it took longer than a cut off we color it red (the error color). Screenshot 2024-09-16 at 11 48 15 PM --- .../src/ReactFiberCommitWork.js | 5 ++ .../src/ReactFiberPerformanceTrack.js | 48 +++++++++++-------- .../src/ReactProfilerTimer.js | 3 ++ 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 4c66470342c89..5965dbe8db0a8 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -109,6 +109,7 @@ import { popComponentEffectStart, componentEffectStartTime, componentEffectEndTime, + componentEffectDuration, } from './ReactProfilerTimer'; import { logComponentRender, @@ -608,6 +609,7 @@ function commitLayoutEffectOnFiber( finishedWork, componentEffectStartTime, componentEffectEndTime, + componentEffectDuration, ); } @@ -2105,6 +2107,7 @@ function commitMutationEffectsOnFiber( finishedWork, componentEffectStartTime, componentEffectEndTime, + componentEffectDuration, ); } @@ -2926,6 +2929,7 @@ function commitPassiveMountOnFiber( finishedWork, componentEffectStartTime, componentEffectEndTime, + componentEffectDuration, ); } @@ -3444,6 +3448,7 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { finishedWork, componentEffectStartTime, componentEffectEndTime, + componentEffectDuration, ); } diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 9c6c7ff8a80d3..a053ea56ffc7f 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -38,24 +38,9 @@ const reusableComponentOptions = { }, }; -const reusableComponentEffectDevToolDetails = { - dataType: 'track-entry', - color: 'secondary', - track: 'Blocking', // Lane - trackGroup: TRACK_GROUP, -}; -const reusableComponentEffectOptions = { - start: -0, - end: -0, - detail: { - devtools: reusableComponentEffectDevToolDetails, - }, -}; - export function setCurrentTrackFromLanes(lanes: number): void { - reusableComponentEffectDevToolDetails.track = - reusableComponentDevToolDetails.track = - getGroupNameOfHighestPriorityLane(lanes); + reusableComponentDevToolDetails.track = + getGroupNameOfHighestPriorityLane(lanes); } export function logComponentRender( @@ -69,6 +54,20 @@ export function logComponentRender( return; } if (supportsUserTiming) { + let selfTime: number = (fiber.actualDuration: any); + if (fiber.alternate === null || fiber.alternate.child !== fiber.child) { + for (let child = fiber.child; child !== null; child = child.sibling) { + selfTime -= (child.actualDuration: any); + } + } + reusableComponentDevToolDetails.color = + selfTime < 0.5 + ? 'primary-light' + : selfTime < 10 + ? 'primary' + : selfTime < 100 + ? 'primary-dark' + : 'error'; reusableComponentOptions.start = startTime; reusableComponentOptions.end = endTime; performance.measure(name, reusableComponentOptions); @@ -79,6 +78,7 @@ export function logComponentEffect( fiber: Fiber, startTime: number, endTime: number, + selfTime: number, ): void { const name = getComponentNameFromFiber(fiber); if (name === null) { @@ -86,8 +86,16 @@ export function logComponentEffect( return; } if (supportsUserTiming) { - reusableComponentEffectOptions.start = startTime; - reusableComponentEffectOptions.end = endTime; - performance.measure(name, reusableComponentEffectOptions); + reusableComponentDevToolDetails.color = + selfTime < 1 + ? 'secondary-light' + : selfTime < 100 + ? 'secondary' + : selfTime < 500 + ? 'secondary-dark' + : 'error'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure(name, reusableComponentOptions); } } diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index da450d7f28f52..d65ca0a7544ee 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -25,6 +25,7 @@ export let completeTime: number = -0; export let commitTime: number = -0; export let profilerStartTime: number = -1.1; export let profilerEffectDuration: number = -0; +export let componentEffectDuration: number = -0; export let componentEffectStartTime: number = -1.1; export let componentEffectEndTime: number = -1.1; @@ -72,6 +73,7 @@ export function pushComponentEffectStart(): number { } const prevEffectStart = componentEffectStartTime; componentEffectStartTime = -1.1; // Track the next start. + componentEffectDuration = -0; // Reset component level duration. return prevEffectStart; } @@ -211,6 +213,7 @@ export function recordEffectDuration(fiber: Fiber): void { // Store duration on the next nearest Profiler ancestor // Or the root (for the DevTools Profiler to read) profilerEffectDuration += elapsedTime; + componentEffectDuration += elapsedTime; // Keep track of the last end time of the effects. componentEffectEndTime = endTime; From 5dcb009760160c085496e943f76090d98528f971 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 18 Sep 2024 11:51:36 -0400 Subject: [PATCH 163/426] [compiler] Add JSX inlining optimization (#30867) This adds an `InlineJsxTransform` optimization pass, toggled by the `enableInlineJsxTransform` flag. When enabled, JSX will be transformed into React Element object literals, preventing runtime overhead during element creation. TODO: - [ ] Add conditionals to make transform PROD-only - [ ] Make the React element symbol configurable so this works with runtimes that support `react.element` or `react.transitional.element` - [ ] Look into additional optimization to pass props spread through directly if none of the properties are mutated --- .../src/Entrypoint/Pipeline.ts | 10 + .../src/HIR/BuildReactiveScopeTerminalsHIR.ts | 16 +- .../src/HIR/Environment.ts | 7 + .../src/HIR/HIRBuilder.ts | 20 + .../src/Optimization/InlineJsxTransform.ts | 402 ++++++++++++++++++ .../src/Optimization/index.ts | 1 + .../compiler/inline-jsx-transform.expect.md | 226 ++++++++++ .../fixtures/compiler/inline-jsx-transform.js | 43 ++ 8 files changed, 711 insertions(+), 14 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index f87d371bed6a3..606440b241f9b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -41,6 +41,7 @@ import { constantPropagation, deadCodeElimination, pruneMaybeThrows, + inlineJsxTransform, } from '../Optimization'; import {instructionReordering} from '../Optimization/InstructionReordering'; import { @@ -351,6 +352,15 @@ function* runWithEnvironment( }); } + if (env.config.enableInlineJsxTransform) { + inlineJsxTransform(hir); + yield log({ + kind: 'hir', + name: 'inlineJsxTransform', + value: hir, + }); + } + const reactiveFunction = buildReactiveFunction(hir); yield log({ kind: 'reactive', diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts index 0999a3492b4a4..7c1fb54ea8058 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildReactiveScopeTerminalsHIR.ts @@ -14,6 +14,7 @@ import { ScopeId, } from './HIR'; import { + fixScopeAndIdentifierRanges, markInstructionIds, markPredecessors, reversePostorderBlocks, @@ -176,20 +177,7 @@ export function buildReactiveScopeTerminalsHIR(fn: HIRFunction): void { * Step 5: * Fix scope and identifier ranges to account for renumbered instructions */ - for (const [, block] of fn.body.blocks) { - const terminal = block.terminal; - if (terminal.kind === 'scope' || terminal.kind === 'pruned-scope') { - /* - * Scope ranges should always align to start at the 'scope' terminal - * and end at the first instruction of the fallthrough block - */ - const fallthroughBlock = fn.body.blocks.get(terminal.fallthrough)!; - const firstId = - fallthroughBlock.instructions[0]?.id ?? fallthroughBlock.terminal.id; - terminal.scope.range.start = terminal.id; - terminal.scope.range.end = firstId; - } - } + fixScopeAndIdentifierRanges(fn.body); } type TerminalRewriteInfo = diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 75f3086011fd0..66270345fdf35 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -233,6 +233,13 @@ const EnvironmentConfigSchema = z.object({ */ enableOptionalDependencies: z.boolean().default(true), + /** + * Enables inlining ReactElement object literals in place of JSX + * An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime + * Currently a prod-only optimization, requiring Fast JSX dependencies + */ + enableInlineJsxTransform: z.boolean().default(false), + /* * Enable validation of hooks to partially check that the component honors the rules of hooks. * When disabled, the component is assumed to follow the rules (though the Babel plugin looks diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts index c694cf310fb39..9202f2145f27e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIRBuilder.ts @@ -912,3 +912,23 @@ export function clonePlaceToTemporary(env: Environment, place: Place): Place { temp.reactive = place.reactive; return temp; } + +/** + * Fix scope and identifier ranges to account for renumbered instructions + */ +export function fixScopeAndIdentifierRanges(func: HIR): void { + for (const [, block] of func.blocks) { + const terminal = block.terminal; + if (terminal.kind === 'scope' || terminal.kind === 'pruned-scope') { + /* + * Scope ranges should always align to start at the 'scope' terminal + * and end at the first instruction of the fallthrough block + */ + const fallthroughBlock = func.blocks.get(terminal.fallthrough)!; + const firstId = + fallthroughBlock.instructions[0]?.id ?? fallthroughBlock.terminal.id; + terminal.scope.range.start = terminal.id; + terminal.scope.range.end = firstId; + } + } +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts new file mode 100644 index 0000000000000..344159d0b6072 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -0,0 +1,402 @@ +/** + * 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 { + BuiltinTag, + Effect, + HIRFunction, + Instruction, + JsxAttribute, + makeInstructionId, + ObjectProperty, + Place, + SpreadPattern, +} from '../HIR'; +import { + createTemporaryPlace, + fixScopeAndIdentifierRanges, + markInstructionIds, + markPredecessors, + reversePostorderBlocks, +} from '../HIR/HIRBuilder'; + +function createSymbolProperty( + fn: HIRFunction, + instr: Instruction, + nextInstructions: Array, + propertyName: string, + symbolName: string, +): ObjectProperty { + const symbolPlace = createTemporaryPlace(fn.env, instr.value.loc); + const symbolInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...symbolPlace, effect: Effect.Mutate}, + value: { + kind: 'LoadGlobal', + binding: {kind: 'Global', name: 'Symbol'}, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + nextInstructions.push(symbolInstruction); + + const symbolForPlace = createTemporaryPlace(fn.env, instr.value.loc); + const symbolForInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...symbolForPlace, effect: Effect.Read}, + value: { + kind: 'PropertyLoad', + object: {...symbolInstruction.lvalue}, + property: 'for', + loc: instr.value.loc, + }, + loc: instr.loc, + }; + nextInstructions.push(symbolForInstruction); + + const symbolValuePlace = createTemporaryPlace(fn.env, instr.value.loc); + const symbolValueInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...symbolValuePlace, effect: Effect.Mutate}, + value: { + kind: 'Primitive', + value: symbolName, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + nextInstructions.push(symbolValueInstruction); + + const $$typeofPlace = createTemporaryPlace(fn.env, instr.value.loc); + const $$typeofInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...$$typeofPlace, effect: Effect.Mutate}, + value: { + kind: 'MethodCall', + receiver: symbolInstruction.lvalue, + property: symbolForInstruction.lvalue, + args: [symbolValueInstruction.lvalue], + loc: instr.value.loc, + }, + loc: instr.loc, + }; + const $$typeofProperty: ObjectProperty = { + kind: 'ObjectProperty', + key: {name: propertyName, kind: 'string'}, + type: 'property', + place: {...$$typeofPlace, effect: Effect.Capture}, + }; + nextInstructions.push($$typeofInstruction); + return $$typeofProperty; +} + +function createTagProperty( + fn: HIRFunction, + instr: Instruction, + nextInstructions: Array, + componentTag: BuiltinTag | Place, +): ObjectProperty { + let tagProperty: ObjectProperty; + switch (componentTag.kind) { + case 'BuiltinTag': { + const tagPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc); + const tagInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...tagPropertyPlace, effect: Effect.Mutate}, + value: { + kind: 'Primitive', + value: componentTag.name, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + tagProperty = { + kind: 'ObjectProperty', + key: {name: 'type', kind: 'string'}, + type: 'property', + place: {...tagPropertyPlace, effect: Effect.Capture}, + }; + nextInstructions.push(tagInstruction); + break; + } + case 'Identifier': { + tagProperty = { + kind: 'ObjectProperty', + key: {name: 'type', kind: 'string'}, + type: 'property', + place: {...componentTag, effect: Effect.Capture}, + }; + break; + } + } + + return tagProperty; +} + +function createPropsProperties( + fn: HIRFunction, + instr: Instruction, + nextInstructions: Array, + propAttributes: Array, + children: Array | null, +): { + refProperty: ObjectProperty; + keyProperty: ObjectProperty; + propsProperty: ObjectProperty; +} { + let refProperty: ObjectProperty | undefined; + let keyProperty: ObjectProperty | undefined; + const props: Array = []; + propAttributes.forEach(prop => { + switch (prop.kind) { + case 'JsxAttribute': { + if (prop.name === 'ref') { + refProperty = { + kind: 'ObjectProperty', + key: {name: 'ref', kind: 'string'}, + type: 'property', + place: {...prop.place}, + }; + } else if (prop.name === 'key') { + keyProperty = { + kind: 'ObjectProperty', + key: {name: 'key', kind: 'string'}, + type: 'property', + place: {...prop.place}, + }; + } else { + const attributeProperty: ObjectProperty = { + kind: 'ObjectProperty', + key: {name: prop.name, kind: 'string'}, + type: 'property', + place: {...prop.place}, + }; + props.push(attributeProperty); + } + break; + } + case 'JsxSpreadAttribute': { + // TODO: Optimize spreads to pass object directly if none of its properties are mutated + props.push({ + kind: 'Spread', + place: {...prop.argument}, + }); + break; + } + } + }); + const propsPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc); + if (children) { + let childrenPropProperty: ObjectProperty; + if (children.length === 1) { + childrenPropProperty = { + kind: 'ObjectProperty', + key: {name: 'children', kind: 'string'}, + type: 'property', + place: {...children[0], effect: Effect.Capture}, + }; + } else { + const childrenPropPropertyPlace = createTemporaryPlace( + fn.env, + instr.value.loc, + ); + + const childrenPropInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...childrenPropPropertyPlace, effect: Effect.Mutate}, + value: { + kind: 'ArrayExpression', + elements: [...children], + loc: instr.value.loc, + }, + loc: instr.loc, + }; + nextInstructions.push(childrenPropInstruction); + childrenPropProperty = { + kind: 'ObjectProperty', + key: {name: 'children', kind: 'string'}, + type: 'property', + place: {...childrenPropPropertyPlace, effect: Effect.Capture}, + }; + } + props.push(childrenPropProperty); + } + + if (refProperty == null) { + const refPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc); + const refInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...refPropertyPlace, effect: Effect.Mutate}, + value: { + kind: 'Primitive', + value: null, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + refProperty = { + kind: 'ObjectProperty', + key: {name: 'ref', kind: 'string'}, + type: 'property', + place: {...refPropertyPlace, effect: Effect.Capture}, + }; + nextInstructions.push(refInstruction); + } + + if (keyProperty == null) { + const keyPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc); + const keyInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...keyPropertyPlace, effect: Effect.Mutate}, + value: { + kind: 'Primitive', + value: null, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + keyProperty = { + kind: 'ObjectProperty', + key: {name: 'key', kind: 'string'}, + type: 'property', + place: {...keyPropertyPlace, effect: Effect.Capture}, + }; + nextInstructions.push(keyInstruction); + } + + const propsInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...propsPropertyPlace, effect: Effect.Mutate}, + value: { + kind: 'ObjectExpression', + properties: props, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + const propsProperty: ObjectProperty = { + kind: 'ObjectProperty', + key: {name: 'props', kind: 'string'}, + type: 'property', + place: {...propsPropertyPlace, effect: Effect.Capture}, + }; + nextInstructions.push(propsInstruction); + return {refProperty, keyProperty, propsProperty}; +} + +// TODO: Make PROD only with conditional statements +export function inlineJsxTransform(fn: HIRFunction): void { + for (const [, block] of fn.body.blocks) { + let nextInstructions: Array | null = null; + for (let i = 0; i < block.instructions.length; i++) { + const instr = block.instructions[i]!; + switch (instr.value.kind) { + case 'JsxExpression': { + nextInstructions ??= block.instructions.slice(0, i); + + const {refProperty, keyProperty, propsProperty} = + createPropsProperties( + fn, + instr, + nextInstructions, + instr.value.props, + instr.value.children, + ); + const reactElementInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...instr.lvalue, effect: Effect.Store}, + value: { + kind: 'ObjectExpression', + properties: [ + createSymbolProperty( + fn, + instr, + nextInstructions, + '$$typeof', + /** + * TODO: Add this to config so we can switch between + * react.element / react.transitional.element + */ + 'react.transitional.element', + ), + createTagProperty(fn, instr, nextInstructions, instr.value.tag), + refProperty, + keyProperty, + propsProperty, + ], + loc: instr.value.loc, + }, + loc: instr.loc, + }; + nextInstructions.push(reactElementInstruction); + + break; + } + case 'JsxFragment': { + nextInstructions ??= block.instructions.slice(0, i); + const {refProperty, keyProperty, propsProperty} = + createPropsProperties( + fn, + instr, + nextInstructions, + [], + instr.value.children, + ); + const reactElementInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...instr.lvalue, effect: Effect.Store}, + value: { + kind: 'ObjectExpression', + properties: [ + createSymbolProperty( + fn, + instr, + nextInstructions, + '$$typeof', + /** + * TODO: Add this to config so we can switch between + * react.element / react.transitional.element + */ + 'react.transitional.element', + ), + createSymbolProperty( + fn, + instr, + nextInstructions, + 'type', + 'react.fragment', + ), + refProperty, + keyProperty, + propsProperty, + ], + loc: instr.value.loc, + }, + loc: instr.loc, + }; + nextInstructions.push(reactElementInstruction); + break; + } + default: { + if (nextInstructions !== null) { + nextInstructions.push(instr); + } + } + } + } + if (nextInstructions !== null) { + block.instructions = nextInstructions; + } + } + + // Fixup the HIR to restore RPO, ensure correct predecessors, and renumber instructions. + reversePostorderBlocks(fn.body); + markPredecessors(fn.body); + markInstructionIds(fn.body); + // The renumbering instructions invalidates scope and identifier ranges + fixScopeAndIdentifierRanges(fn.body); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/index.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/index.ts index 722b05a809960..bb060b8dc285c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/index.ts @@ -8,3 +8,4 @@ export {constantPropagation} from './ConstantPropagation'; export {deadCodeElimination} from './DeadCodeElimination'; export {pruneMaybeThrows} from './PruneMaybeThrows'; +export {inlineJsxTransform} from './InlineJsxTransform'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md new file mode 100644 index 0000000000000..f399317925c64 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -0,0 +1,226 @@ + +## Input + +```javascript +// @enableInlineJsxTransform + +function Parent({children, a: _a, b: _b, c: _c, ref}) { + return
{children}
; +} + +function Child({children}) { + return <>{children}; +} + +function GrandChild({className}) { + return ( + + Hello world + + ); +} + +function ParentAndRefAndKey(props) { + const testRef = useRef(); + return ; +} + +function ParentAndChildren(props) { + return ( + + + + + + + ); +} + +const propsToSpread = {a: 'a', b: 'b', c: 'c'}; +function PropsSpread() { + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: ParentAndChildren, + params: [{foo: 'abc'}], +}; + +``` + +## Code + +```javascript +import { c as _c2 } from "react/compiler-runtime"; // @enableInlineJsxTransform + +function Parent(t0) { + const $ = _c2(2); + const { children, ref } = t0; + let t1; + if ($[0] !== children) { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: "div", + ref: ref, + key: null, + props: { children: children }, + }; + $[0] = children; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +function Child(t0) { + const $ = _c2(2); + const { children } = t0; + let t1; + if ($[0] !== children) { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Symbol.for("react.fragment"), + ref: null, + key: null, + props: { children: children }, + }; + $[0] = children; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +function GrandChild(t0) { + const $ = _c2(3); + const { className } = t0; + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: React.Fragment, + ref: null, + key: "fragmentKey", + props: { children: "Hello world" }, + }; + $[0] = t1; + } else { + t1 = $[0]; + } + let t2; + if ($[1] !== className) { + t2 = { + $$typeof: Symbol.for("react.transitional.element"), + type: "span", + ref: null, + key: null, + props: { className: className, children: t1 }, + }; + $[1] = className; + $[2] = t2; + } else { + t2 = $[2]; + } + return t2; +} + +function ParentAndRefAndKey(props) { + const $ = _c2(1); + const testRef = useRef(); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Parent, + ref: testRef, + key: "testKey", + props: { a: "a", b: { b: "b" }, c: C }, + }; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +function ParentAndChildren(props) { + const $ = _c2(3); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Child, + ref: null, + key: "a", + props: {}, + }; + $[0] = t0; + } else { + t0 = $[0]; + } + let t1; + if ($[1] !== props.foo) { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Parent, + ref: null, + key: null, + props: { + children: [ + t0, + { + $$typeof: Symbol.for("react.transitional.element"), + type: Child, + ref: null, + key: "b", + props: { + children: { + $$typeof: Symbol.for("react.transitional.element"), + type: GrandChild, + ref: null, + key: null, + props: { className: props.foo }, + }, + }, + }, + ], + }, + }; + $[1] = props.foo; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +const propsToSpread = { a: "a", b: "b", c: "c" }; +function PropsSpread() { + const $ = _c2(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Test, + ref: null, + key: null, + props: { ...propsToSpread }, + }; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: ParentAndChildren, + params: [{ foo: "abc" }], +}; + +``` + +### Eval output +(kind: ok)
Hello world
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js new file mode 100644 index 0000000000000..29acaf60d276f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js @@ -0,0 +1,43 @@ +// @enableInlineJsxTransform + +function Parent({children, a: _a, b: _b, c: _c, ref}) { + return
{children}
; +} + +function Child({children}) { + return <>{children}; +} + +function GrandChild({className}) { + return ( + + Hello world + + ); +} + +function ParentAndRefAndKey(props) { + const testRef = useRef(); + return ; +} + +function ParentAndChildren(props) { + return ( + + + + + + + ); +} + +const propsToSpread = {a: 'a', b: 'b', c: 'c'}; +function PropsSpread() { + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: ParentAndChildren, + params: [{foo: 'abc'}], +}; From 5e83d9ab3b3f88853591dff43cd70ee4e5c90c5d Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 17:37:00 +0100 Subject: [PATCH 164/426] feat[react-devtools]: add settings to global hook object (#30564) Right now we are patching console 2 times: when hook is installed (before page is loaded) and when backend is connected. Because of this, even if user had `appendComponentStack` setting enabled, all emitted error and warning logs are not going to have component stacks appended. They also won't have component stacks appended retroactively when user opens browser DevTools (this is when frontend is initialized and connects to backend). This behavior adds potential race conditions with LogBox in React Native, and also unpredictable to the user, because in order to get component stacks logged you have to open browser DevTools, but by the time you do it, error or warning log was already emitted. To solve this, we are going to only patch console in the hook object, because it is guaranteed to load even before React. Settings are going to be synchronized with the hook via Bridge, and React DevTools Backend Host (React Native or browser extension shell) will be responsible for persisting these settings across the session, this is going to be implemented in a separate PR. --- .../src/backend/agent.js | 39 +++++++------------ .../src/backend/console.js | 2 +- .../src/backend/index.js | 4 ++ .../src/backend/types.js | 8 ++++ packages/react-devtools-shared/src/hook.js | 28 ++++++++++++- 5 files changed, 55 insertions(+), 26 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index f4665e014c023..8112fdcd2584b 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -37,11 +37,9 @@ import type { RendererID, RendererInterface, ConsolePatchSettings, + DevToolsHookSettings, } from './types'; -import type { - ComponentFilter, - BrowserTheme, -} from 'react-devtools-shared/src/frontend/types'; +import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types'; import {isSynchronousXHRSupported, isReactNativeEnvironment} from './utils'; const debug = (methodName: string, ...args: Array) => { @@ -153,6 +151,7 @@ export default class Agent extends EventEmitter<{ drawTraceUpdates: [Array], disableTraceUpdates: [], getIfHasUnsupportedRendererVersion: [], + updateHookSettings: [DevToolsHookSettings], }> { _bridge: BackendBridge; _isProfiling: boolean = false; @@ -805,30 +804,22 @@ export default class Agent extends EventEmitter<{ } }; - updateConsolePatchSettings: ({ - appendComponentStack: boolean, - breakOnConsoleErrors: boolean, - browserTheme: BrowserTheme, - hideConsoleLogsInStrictMode: boolean, - showInlineWarningsAndErrors: boolean, - }) => void = ({ - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - browserTheme, - }: ConsolePatchSettings) => { + updateConsolePatchSettings: ( + settings: $ReadOnly, + ) => void = settings => { + // Propagate the settings, so Backend can subscribe to it and modify hook + this.emit('updateHookSettings', { + appendComponentStack: settings.appendComponentStack, + breakOnConsoleErrors: settings.breakOnConsoleErrors, + showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors, + hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode, + }); + // If the frontend preferences have changed, // or in the case of React Native- if the backend is just finding out the preferences- // then reinstall the console overrides. // It's safe to call `patchConsole` multiple times. - patchConsole({ - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - browserTheme, - }); + patchConsole(settings); }; updateComponentFilters: (componentFilters: Array) => void = diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index 61d2e490eb966..ecca4c94246c6 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -135,7 +135,7 @@ export function patch({ showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, browserTheme, -}: ConsolePatchSettings): void { +}: $ReadOnly): void { // Settings may change after we've patched the console. // Using a shared ref allows the patch function to read the latest values. consoleSettingsRef.appendComponentStack = appendComponentStack; diff --git a/packages/react-devtools-shared/src/backend/index.js b/packages/react-devtools-shared/src/backend/index.js index 0ac7ecc468aa5..5d84bf6bb70f0 100644 --- a/packages/react-devtools-shared/src/backend/index.js +++ b/packages/react-devtools-shared/src/backend/index.js @@ -83,6 +83,10 @@ export function initBackend( agent.removeListener('shutdown', onAgentShutdown); }); + agent.addListener('updateHookSettings', settings => { + hook.settings = settings; + }); + return () => { subs.forEach(fn => fn()); }; diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 7d816d403af07..5c014bba8051f 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -527,6 +527,7 @@ export type DevToolsHook = { // Testing dangerous_setTargetConsoleForTesting?: (fakeConsole: Object) => void, + settings?: DevToolsHookSettings, ... }; @@ -537,3 +538,10 @@ export type ConsolePatchSettings = { hideConsoleLogsInStrictMode: boolean, browserTheme: BrowserTheme, }; + +export type DevToolsHookSettings = { + appendComponentStack: boolean, + breakOnConsoleErrors: boolean, + showInlineWarningsAndErrors: boolean, + hideConsoleLogsInStrictMode: boolean, +}; diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index eb81e81d4615e..1dd1fcbd4c455 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -15,6 +15,7 @@ import type { RendererID, RendererInterface, DevToolsBackend, + DevToolsHookSettings, } from './backend/types'; import { @@ -25,7 +26,12 @@ import attachRenderer from './attachRenderer'; declare var window: any; -export function installHook(target: any): DevToolsHook | null { +export function installHook( + target: any, + maybeSettingsOrSettingsPromise?: + | DevToolsHookSettings + | Promise, +): DevToolsHook | null { if (target.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { return null; } @@ -566,6 +572,26 @@ export function installHook(target: any): DevToolsHook | null { registerInternalModuleStop, }; + if (maybeSettingsOrSettingsPromise == null) { + // Set default settings + hook.settings = { + appendComponentStack: true, + breakOnConsoleErrors: false, + showInlineWarningsAndErrors: true, + hideConsoleLogsInStrictMode: false, + }; + } else { + Promise.resolve(maybeSettingsOrSettingsPromise) + .then(settings => { + hook.settings = settings; + }) + .catch(() => { + targetConsole.error( + "React DevTools failed to get Console Patching settings. Console won't be patched and some console features will not work.", + ); + }); + } + if (__TEST__) { hook.dangerous_setTargetConsoleForTesting = dangerous_setTargetConsoleForTesting; From b521ef8a2aaff61154e59f6d0d3791ee4dbe6395 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 18:02:13 +0100 Subject: [PATCH 165/426] refactor[react-devtools]: remove browserTheme from ConsolePatchSettings (#30566) Stacked on https://github.com/facebook/react/pull/30564. We are no longer using browser theme in our console patching, this was removed in unification of console patching for strict mode, we started using ansi escape symbols and forking based on browser theme is no longer required - https://github.com/facebook/react/pull/29869 The real browser theme initialization for frontend is happening at the other place and is not affected: https://github.com/facebook/react/blob/40be968257a7a10a267210670103f20dd0429ef3/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js#L117-L120 --- packages/react-devtools-core/src/cachedSettings.js | 5 ++--- .../src/main/syncSavedPreferences.js | 4 ---- .../react-devtools-shared/src/backend/console.js | 9 +-------- packages/react-devtools-shared/src/backend/types.js | 12 +++--------- .../src/devtools/views/Settings/SettingsContext.js | 2 -- 5 files changed, 6 insertions(+), 26 deletions(-) diff --git a/packages/react-devtools-core/src/cachedSettings.js b/packages/react-devtools-core/src/cachedSettings.js index 18ecd696b3c7c..afe12bfdbc5ad 100644 --- a/packages/react-devtools-core/src/cachedSettings.js +++ b/packages/react-devtools-core/src/cachedSettings.js @@ -9,7 +9,7 @@ import type {ConsolePatchSettings} from 'react-devtools-shared/src/backend/types'; import {writeConsolePatchSettingsToWindow} from 'react-devtools-shared/src/backend/console'; -import {castBool, castBrowserTheme} from 'react-devtools-shared/src/utils'; +import {castBool} from 'react-devtools-shared/src/utils'; // Note: all keys should be optional in this type, because users can use newer // versions of React DevTools with older versions of React Native, and the object @@ -54,14 +54,13 @@ function parseConsolePatchSettings( breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, - browserTheme, } = parsedValue; + return { appendComponentStack: castBool(appendComponentStack) ?? true, breakOnConsoleErrors: castBool(breakOnConsoleErrors) ?? false, showInlineWarningsAndErrors: castBool(showInlineWarningsAndErrors) ?? true, hideConsoleLogsInStrictMode: castBool(hideConsoleLogsInStrictMode) ?? false, - browserTheme: castBrowserTheme(browserTheme) ?? 'dark', }; } diff --git a/packages/react-devtools-extensions/src/main/syncSavedPreferences.js b/packages/react-devtools-extensions/src/main/syncSavedPreferences.js index 6ceed86fcd06d..f22d41eb7c904 100644 --- a/packages/react-devtools-extensions/src/main/syncSavedPreferences.js +++ b/packages/react-devtools-extensions/src/main/syncSavedPreferences.js @@ -7,7 +7,6 @@ import { getShowInlineWarningsAndErrors, getHideConsoleLogsInStrictMode, } from 'react-devtools-shared/src/utils'; -import {getBrowserTheme} from 'react-devtools-extensions/src/utils'; // The renderer interface can't read saved component filters directly, // because they are stored in localStorage within the context of the extension. @@ -28,9 +27,6 @@ function syncSavedPreferences() { )}; window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = ${JSON.stringify( getHideConsoleLogsInStrictMode(), - )}; - window.__REACT_DEVTOOLS_BROWSER_THEME__ = ${JSON.stringify( - getBrowserTheme(), )};`, ); } diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index ecca4c94246c6..0b6b19626a9bb 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -22,7 +22,7 @@ import { ANSI_STYLE_DIMMING_TEMPLATE, ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK, } from 'react-devtools-shared/src/constants'; -import {castBool, castBrowserTheme} from '../utils'; +import {castBool} from '../utils'; const OVERRIDE_CONSOLE_METHODS = ['error', 'trace', 'warn']; @@ -124,7 +124,6 @@ const consoleSettingsRef: ConsolePatchSettings = { breakOnConsoleErrors: false, showInlineWarningsAndErrors: false, hideConsoleLogsInStrictMode: false, - browserTheme: 'dark', }; // Patches console methods to append component stack for the current fiber. @@ -134,7 +133,6 @@ export function patch({ breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, - browserTheme, }: $ReadOnly): void { // Settings may change after we've patched the console. // Using a shared ref allows the patch function to read the latest values. @@ -142,7 +140,6 @@ export function patch({ consoleSettingsRef.breakOnConsoleErrors = breakOnConsoleErrors; consoleSettingsRef.showInlineWarningsAndErrors = showInlineWarningsAndErrors; consoleSettingsRef.hideConsoleLogsInStrictMode = hideConsoleLogsInStrictMode; - consoleSettingsRef.browserTheme = browserTheme; if ( appendComponentStack || @@ -412,15 +409,12 @@ export function patchConsoleUsingWindowValues() { const hideConsoleLogsInStrictMode = castBool(window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__) ?? false; - const browserTheme = - castBrowserTheme(window.__REACT_DEVTOOLS_BROWSER_THEME__) ?? 'dark'; patch({ appendComponentStack, breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, - browserTheme, }); } @@ -438,7 +432,6 @@ export function writeConsolePatchSettingsToWindow( settings.showInlineWarningsAndErrors; window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = settings.hideConsoleLogsInStrictMode; - window.__REACT_DEVTOOLS_BROWSER_THEME__ = settings.browserTheme; } export function installConsoleFunctionsToWindow(): void { diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 5c014bba8051f..fa9949e3ddc5d 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -31,7 +31,6 @@ import type { } from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; import type {InitBackend} from 'react-devtools-shared/src/backend'; import type {TimelineDataExport} from 'react-devtools-timeline/src/types'; -import type {BrowserTheme} from 'react-devtools-shared/src/frontend/types'; import type {BackendBridge} from 'react-devtools-shared/src/bridge'; import type {Source} from 'react-devtools-shared/src/shared/types'; import type Agent from './agent'; @@ -531,17 +530,12 @@ export type DevToolsHook = { ... }; -export type ConsolePatchSettings = { - appendComponentStack: boolean, - breakOnConsoleErrors: boolean, - showInlineWarningsAndErrors: boolean, - hideConsoleLogsInStrictMode: boolean, - browserTheme: BrowserTheme, -}; - export type DevToolsHookSettings = { appendComponentStack: boolean, breakOnConsoleErrors: boolean, showInlineWarningsAndErrors: boolean, hideConsoleLogsInStrictMode: boolean, }; + +// Will be removed together with console patching from backend/console.js to hook.js +export type ConsolePatchSettings = DevToolsHookSettings; diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js index a6f2c5e8c2a78..33487c2f553d6 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js @@ -202,7 +202,6 @@ function SettingsContextController({ breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, - browserTheme, }); }, [ bridge, @@ -210,7 +209,6 @@ function SettingsContextController({ breakOnConsoleErrors, showInlineWarningsAndErrors, hideConsoleLogsInStrictMode, - browserTheme, ]); useEffect(() => { From 3cac0875dcd60b8db099d8fa671c5ad1f8f0ef23 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 18:12:18 +0100 Subject: [PATCH 166/426] refactor[react-devtools]: move console patching to global hook (#30596) Stacked on https://github.com/facebook/react/pull/30566 and whats under it. See [this commit](https://github.com/facebook/react/pull/30596/commits/374fd737e4b0b7028afb765838db7c0e22def865). It is mostly copying code from one place to another and updating tests. With these changes, for every console method that we patch, there is going to be a single applied patch: - For `error`, `warn`, and `trace` we are patching when hook is installed. This guarantees that component stacks are going to be appended even if browser DevTools are not opened. We pay some price for it, though: if user has browser DevTools closed and if at this point some warning or error is emitted (logged), the next time user opens browser DevTools, they are going to see `hook.js` as the source frame. Unfortunately, ignore listing from source maps is not applied retroactively, and I don't know if its a bug or just a design limitations. Once browser DevTools are opened, source maps will be loaded and ignore listing will be applied for all emitted logs in the future. - For `log`, `info`, `group`, `groupCollapsed` we are only patching when React notifies React DevTools about running in StrictMode. We unpatch the methods right after it. --- packages/react-devtools-core/src/backend.js | 4 - packages/react-devtools-inline/src/backend.js | 4 - .../src/__tests__/componentStacks-test.js | 62 +- .../src/__tests__/console-test.js | 973 +++++------------- .../src/__tests__/setupTests.js | 144 ++- .../src/backend/agent.js | 10 +- .../src/backend/console.js | 418 +------- .../src/backend/fiber/renderer.js | 18 - .../src/backend/flight/renderer.js | 10 - .../src/backend/legacy/renderer.js | 6 - .../src/backend/types.js | 2 - packages/react-devtools-shared/src/bridge.js | 4 +- packages/react-devtools-shared/src/hook.js | 408 +++++--- 13 files changed, 680 insertions(+), 1383 deletions(-) diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index 25001502f1c2b..d588d4f91e9f0 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -11,7 +11,6 @@ import Agent from 'react-devtools-shared/src/backend/agent'; import Bridge from 'react-devtools-shared/src/bridge'; import {installHook} from 'react-devtools-shared/src/hook'; import {initBackend} from 'react-devtools-shared/src/backend'; -import {installConsoleFunctionsToWindow} from 'react-devtools-shared/src/backend/console'; import {__DEBUG__} from 'react-devtools-shared/src/constants'; import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils'; @@ -41,9 +40,6 @@ type ConnectOptions = { devToolsSettingsManager: ?DevToolsSettingsManager, }; -// Install a global variable to allow patching console early (during injection). -// This provides React Native developers with components stacks even if they don't run DevTools. -installConsoleFunctionsToWindow(); installHook(window); const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/packages/react-devtools-inline/src/backend.js b/packages/react-devtools-inline/src/backend.js index e7d0485b37569..fca1535c4e5ba 100644 --- a/packages/react-devtools-inline/src/backend.js +++ b/packages/react-devtools-inline/src/backend.js @@ -3,7 +3,6 @@ import Agent from 'react-devtools-shared/src/backend/agent'; import Bridge from 'react-devtools-shared/src/bridge'; import {initBackend} from 'react-devtools-shared/src/backend'; -import {installConsoleFunctionsToWindow} from 'react-devtools-shared/src/backend/console'; import {installHook} from 'react-devtools-shared/src/hook'; import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; @@ -120,8 +119,5 @@ export function createBridge(contentWindow: any, wall?: Wall): BackendBridge { } export function initialize(contentWindow: any): void { - // Install a global variable to allow patching console early (during injection). - // This provides React Native developers with components stacks even if they don't run DevTools. - installConsoleFunctionsToWindow(); installHook(contentWindow); } diff --git a/packages/react-devtools-shared/src/__tests__/componentStacks-test.js b/packages/react-devtools-shared/src/__tests__/componentStacks-test.js index b99db5c540097..54af62db44e92 100644 --- a/packages/react-devtools-shared/src/__tests__/componentStacks-test.js +++ b/packages/react-devtools-shared/src/__tests__/componentStacks-test.js @@ -7,27 +7,17 @@ * @flow */ -import {getVersionedRenderImplementation, normalizeCodeLocInfo} from './utils'; +import { + getVersionedRenderImplementation, + normalizeCodeLocInfo, +} from 'react-devtools-shared/src/__tests__/utils'; describe('component stack', () => { let React; let act; - let mockError; - let mockWarn; let supportsOwnerStacks; beforeEach(() => { - // Intercept native console methods before DevTools bootstraps. - // Normalize component stack locations. - mockError = jest.fn(); - mockWarn = jest.fn(); - console.error = (...args) => { - mockError(...args.map(normalizeCodeLocInfo)); - }; - console.warn = (...args) => { - mockWarn(...args.map(normalizeCodeLocInfo)); - }; - const utils = require('./utils'); act = utils.act; @@ -54,18 +44,22 @@ describe('component stack', () => { act(() => render()); - expect(mockError).toHaveBeenCalledWith( + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ 'Test error.', '\n in Child (at **)' + '\n in Parent (at **)' + '\n in Grandparent (at **)', - ); - expect(mockWarn).toHaveBeenCalledWith( + ]); + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ 'Test warning.', '\n in Child (at **)' + '\n in Parent (at **)' + '\n in Grandparent (at **)', - ); + ]); }); // This test should have caught #19911 @@ -89,13 +83,15 @@ describe('component stack', () => { expect(useEffectCount).toBe(1); - expect(mockWarn).toHaveBeenCalledWith( + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ 'Warning to trigger appended component stacks.', '\n in Example (at **)', - ); + ]); }); - // @reactVersion >=18.3 + // @reactVersion >= 18.3 it('should log the current component stack with debug info from promises', () => { const Child = () => { console.error('Test error.'); @@ -117,23 +113,27 @@ describe('component stack', () => { act(() => render()); - expect(mockError).toHaveBeenCalledWith( + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ 'Test error.', supportsOwnerStacks ? '\n in Child (at **)' : '\n in Child (at **)' + - '\n in ServerComponent (at **)' + - '\n in Parent (at **)' + - '\n in Grandparent (at **)', - ); - expect(mockWarn).toHaveBeenCalledWith( + '\n in ServerComponent (at **)' + + '\n in Parent (at **)' + + '\n in Grandparent (at **)', + ]); + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ 'Test warning.', supportsOwnerStacks ? '\n in Child (at **)' : '\n in Child (at **)' + - '\n in ServerComponent (at **)' + - '\n in Parent (at **)' + - '\n in Grandparent (at **)', - ); + '\n in ServerComponent (at **)' + + '\n in Parent (at **)' + + '\n in Grandparent (at **)', + ]); }); }); diff --git a/packages/react-devtools-shared/src/__tests__/console-test.js b/packages/react-devtools-shared/src/__tests__/console-test.js index 516762132e884..00d6d9712679a 100644 --- a/packages/react-devtools-shared/src/__tests__/console-test.js +++ b/packages/react-devtools-shared/src/__tests__/console-test.js @@ -7,52 +7,25 @@ * @flow */ -import {getVersionedRenderImplementation, normalizeCodeLocInfo} from './utils'; +import { + getVersionedRenderImplementation, + normalizeCodeLocInfo, +} from 'react-devtools-shared/src/__tests__/utils'; let React; let ReactDOMClient; let act; -let fakeConsole; -let mockError; -let mockInfo; -let mockGroup; -let mockGroupCollapsed; -let mockLog; -let mockWarn; -let patchConsole; -let unpatchConsole; let rendererID; let supportsOwnerStacks = false; describe('console', () => { beforeEach(() => { - const Console = require('react-devtools-shared/src/backend/console'); - - patchConsole = Console.patch; - unpatchConsole = Console.unpatch; - - // Patch a fake console so we can verify with tests below. - // Patching the real console is too complicated, - // because Jest itself has hooks into it as does our test env setup. - mockError = jest.fn(); - mockInfo = jest.fn(); - mockGroup = jest.fn(); - mockGroupCollapsed = jest.fn(); - mockLog = jest.fn(); - mockWarn = jest.fn(); - fakeConsole = { - error: mockError, - info: mockInfo, - log: mockLog, - warn: mockWarn, - group: mockGroup, - groupCollapsed: mockGroupCollapsed, - }; + const inject = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = internals => { + rendererID = inject(internals); - Console.dangerous_setTargetConsoleForTesting(fakeConsole); - global.__REACT_DEVTOOLS_GLOBAL_HOOK__.dangerous_setTargetConsoleForTesting( - fakeConsole, - ); + return rendererID; + }; React = require('react'); if ( @@ -69,137 +42,44 @@ describe('console', () => { const {render} = getVersionedRenderImplementation(); - // @reactVersion >=18.0 - it('should not patch console methods that are not explicitly overridden', () => { - expect(fakeConsole.error).not.toBe(mockError); - expect(fakeConsole.info).toBe(mockInfo); - expect(fakeConsole.log).toBe(mockLog); - expect(fakeConsole.warn).not.toBe(mockWarn); - expect(fakeConsole.group).toBe(mockGroup); - expect(fakeConsole.groupCollapsed).toBe(mockGroupCollapsed); - }); - - // @reactVersion >=18.0 - it('should patch the console when appendComponentStack is enabled', () => { - unpatchConsole(); - - expect(fakeConsole.error).toBe(mockError); - expect(fakeConsole.warn).toBe(mockWarn); - - patchConsole({ - appendComponentStack: true, - breakOnConsoleErrors: false, - showInlineWarningsAndErrors: false, - }); - - expect(fakeConsole.error).not.toBe(mockError); - expect(fakeConsole.warn).not.toBe(mockWarn); - }); - - // @reactVersion >=18.0 - it('should patch the console when breakOnConsoleErrors is enabled', () => { - unpatchConsole(); - - expect(fakeConsole.error).toBe(mockError); - expect(fakeConsole.warn).toBe(mockWarn); - - patchConsole({ - appendComponentStack: false, - breakOnConsoleErrors: true, - showInlineWarningsAndErrors: false, - }); - - expect(fakeConsole.error).not.toBe(mockError); - expect(fakeConsole.warn).not.toBe(mockWarn); - }); - - // @reactVersion >=18.0 - it('should patch the console when showInlineWarningsAndErrors is enabled', () => { - unpatchConsole(); - - expect(fakeConsole.error).toBe(mockError); - expect(fakeConsole.warn).toBe(mockWarn); - - patchConsole({ - appendComponentStack: false, - breakOnConsoleErrors: false, - showInlineWarningsAndErrors: true, - }); - - expect(fakeConsole.error).not.toBe(mockError); - expect(fakeConsole.warn).not.toBe(mockWarn); - }); - - // @reactVersion >=18.0 - it('should only patch the console once', () => { - const {error, warn} = fakeConsole; - - patchConsole({ - appendComponentStack: true, - breakOnConsoleErrors: false, - showInlineWarningsAndErrors: false, - }); - - expect(fakeConsole.error).toBe(error); - expect(fakeConsole.warn).toBe(warn); - }); - - // @reactVersion >=18.0 - it('should un-patch when requested', () => { - expect(fakeConsole.error).not.toBe(mockError); - expect(fakeConsole.warn).not.toBe(mockWarn); + // @reactVersion >= 18.0 + it('should pass through logs when there is no current fiber', () => { + expect(global.consoleLogMock).toHaveBeenCalledTimes(0); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(0); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(0); - unpatchConsole(); + console.log('log'); + console.warn('warn'); + console.error('error'); - expect(fakeConsole.error).toBe(mockError); - expect(fakeConsole.warn).toBe(mockWarn); + expect(global.consoleLogMock.mock.calls).toEqual([['log']]); + expect(global.consoleWarnMock.mock.calls).toEqual([['warn']]); + expect(global.consoleErrorMock.mock.calls).toEqual([['error']]); }); - // @reactVersion >=18.0 - it('should pass through logs when there is no current fiber', () => { - expect(mockLog).toHaveBeenCalledTimes(0); - expect(mockWarn).toHaveBeenCalledTimes(0); - expect(mockError).toHaveBeenCalledTimes(0); - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - }); - - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should not append multiple stacks', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = true; const Child = ({children}) => { - fakeConsole.warn('warn\n in Child (at fake.js:123)'); - fakeConsole.error('error', '\n in Child (at fake.js:123)'); + console.warn('warn', '\n in Child (at fake.js:123)'); + console.error('error', '\n in Child (at fake.js:123)'); return null; }; act(() => render()); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe( - 'warn\n in Child (at fake.js:123)', - ); - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[0][1]).toBe('\n in Child (at fake.js:123)'); + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual(['warn', '\n in Child (at **)']); + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual(['error', '\n in Child (at **)']); }); - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should append component stacks to errors and warnings logged during render', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = true; const Intermediate = ({children}) => children; const Parent = ({children}) => ( @@ -208,36 +88,34 @@ describe('console', () => { ); const Child = ({children}) => { - fakeConsole.error('error'); - fakeConsole.log('log'); - fakeConsole.warn('warn'); + console.error('error'); + console.log('log'); + console.warn('warn'); return null; }; act(() => render()); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( + expect(global.consoleLogMock.mock.calls).toEqual([['log']]); + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'warn', supportsOwnerStacks ? '\n in Child (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( + ]); + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'error', supportsOwnerStacks ? '\n in Child (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); + ]); }); - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should append component stacks to errors and warnings logged from effects', () => { const Intermediate = ({children}) => children; const Parent = ({children}) => ( @@ -247,60 +125,63 @@ describe('console', () => { ); const Child = ({children}) => { React.useLayoutEffect(function Child_useLayoutEffect() { - fakeConsole.error('active error'); - fakeConsole.log('active log'); - fakeConsole.warn('active warn'); + console.error('active error'); + console.log('active log'); + console.warn('active warn'); }); React.useEffect(function Child_useEffect() { - fakeConsole.error('passive error'); - fakeConsole.log('passive log'); - fakeConsole.warn('passive warn'); + console.error('passive error'); + console.log('passive log'); + console.warn('passive warn'); }); return null; }; act(() => render()); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('active log'); - expect(mockLog.mock.calls[1]).toHaveLength(1); - expect(mockLog.mock.calls[1][0]).toBe('passive log'); - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(mockWarn.mock.calls[0][0]).toBe('active warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( + expect(global.consoleLogMock.mock.calls).toEqual([ + ['active log'], + ['passive log'], + ]); + + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'active warn', supportsOwnerStacks ? '\n in Child_useLayoutEffect (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockWarn.mock.calls[1]).toHaveLength(2); - expect(mockWarn.mock.calls[1][0]).toBe('passive warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][1])).toEqual( + ]); + expect( + global.consoleWarnMock.mock.calls[1].map(normalizeCodeLocInfo), + ).toEqual([ + 'passive warn', supportsOwnerStacks ? '\n in Child_useEffect (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('active error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( + ]); + + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'active error', supportsOwnerStacks ? '\n in Child_useLayoutEffect (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError.mock.calls[1]).toHaveLength(2); - expect(mockError.mock.calls[1][0]).toBe('passive error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[1][1])).toBe( + ]); + expect( + global.consoleErrorMock.mock.calls[1].map(normalizeCodeLocInfo), + ).toEqual([ + 'passive error', supportsOwnerStacks ? '\n in Child_useEffect (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); + ]); }); - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should append component stacks to errors and warnings logged from commit hooks', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = true; const Intermediate = ({children}) => children; const Parent = ({children}) => ( @@ -310,14 +191,14 @@ describe('console', () => { ); class Child extends React.Component { componentDidMount() { - fakeConsole.error('didMount error'); - fakeConsole.log('didMount log'); - fakeConsole.warn('didMount warn'); + console.error('didMount error'); + console.log('didMount log'); + console.warn('didMount warn'); } componentDidUpdate() { - fakeConsole.error('didUpdate error'); - fakeConsole.log('didUpdate log'); - fakeConsole.warn('didUpdate warn'); + console.error('didUpdate error'); + console.log('didUpdate log'); + console.warn('didUpdate warn'); } render() { return null; @@ -327,44 +208,47 @@ describe('console', () => { act(() => render()); act(() => render()); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('didMount log'); - expect(mockLog.mock.calls[1]).toHaveLength(1); - expect(mockLog.mock.calls[1][0]).toBe('didUpdate log'); - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(mockWarn.mock.calls[0][0]).toBe('didMount warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( + expect(global.consoleLogMock.mock.calls).toEqual([ + ['didMount log'], + ['didUpdate log'], + ]); + + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'didMount warn', supportsOwnerStacks ? '\n in Child.componentDidMount (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockWarn.mock.calls[1]).toHaveLength(2); - expect(mockWarn.mock.calls[1][0]).toBe('didUpdate warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][1])).toEqual( + ]); + expect( + global.consoleWarnMock.mock.calls[1].map(normalizeCodeLocInfo), + ).toEqual([ + 'didUpdate warn', supportsOwnerStacks ? '\n in Child.componentDidUpdate (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('didMount error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( + ]); + + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'didMount error', supportsOwnerStacks ? '\n in Child.componentDidMount (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError.mock.calls[1]).toHaveLength(2); - expect(mockError.mock.calls[1][0]).toBe('didUpdate error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[1][1])).toBe( + ]); + expect( + global.consoleErrorMock.mock.calls[1].map(normalizeCodeLocInfo), + ).toEqual([ + 'didUpdate error', supportsOwnerStacks ? '\n in Child.componentDidUpdate (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); + ]); }); - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should append component stacks to errors and warnings logged from gDSFP', () => { const Intermediate = ({children}) => children; const Parent = ({children}) => ( @@ -375,9 +259,9 @@ describe('console', () => { class Child extends React.Component { state = {}; static getDerivedStateFromProps() { - fakeConsole.error('error'); - fakeConsole.log('log'); - fakeConsole.warn('warn'); + console.error('error'); + console.log('log'); + console.warn('warn'); return null; } render() { @@ -387,71 +271,27 @@ describe('console', () => { act(() => render()); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( + expect(global.consoleLogMock.mock.calls).toEqual([['log']]); + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'warn', supportsOwnerStacks ? '\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( + ]); + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'error', supportsOwnerStacks ? '\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - }); - - // @reactVersion >=18.0 - it('should append stacks after being uninstalled and reinstalled', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - - const Child = ({children}) => { - fakeConsole.warn('warn'); - fakeConsole.error('error'); - return null; - }; - - act(() => render()); - - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - - patchConsole({ - appendComponentStack: true, - breakOnConsoleErrors: false, - showInlineWarningsAndErrors: false, - }); - act(() => render()); - - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[1]).toHaveLength(2); - expect(mockWarn.mock.calls[1][0]).toBe('warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][1])).toEqual( - '\n in Child (at **)', - ); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[1]).toHaveLength(2); - expect(mockError.mock.calls[1][0]).toBe('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[1][1])).toBe( - '\n in Child (at **)', - ); + ]); }); - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should be resilient to prepareStackTrace', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true; - Error.prepareStackTrace = function (error, callsites) { const stack = ['An error occurred:', error.message]; for (let i = 0; i < callsites.length; i++) { @@ -473,62 +313,66 @@ describe('console', () => { ); const Child = ({children}) => { - fakeConsole.error('error'); - fakeConsole.log('log'); - fakeConsole.warn('warn'); + console.error('error'); + console.log('log'); + console.warn('warn'); return null; }; act(() => render()); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( + expect(global.consoleLogMock.mock.calls).toEqual([['log']]); + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'warn', supportsOwnerStacks ? '\n in Child (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( + ]); + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'error', supportsOwnerStacks ? '\n in Child (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); + ]); }); - // @reactVersion >=18.0 + // @reactVersion >= 18.0 it('should correctly log Symbols', () => { + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + const Component = ({children}) => { - fakeConsole.warn('Symbol:', Symbol('')); + console.warn('Symbol:', Symbol('')); return null; }; act(() => render()); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0][0]).toBe('Symbol:'); + expect(global.consoleWarnMock.mock.calls).toMatchInlineSnapshot(` + [ + [ + "Symbol:", + Symbol(), + ], + ] + `); }); it('should double log if hideConsoleLogsInStrictMode is disabled in Strict mode', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); - fakeConsole.info('info'); - fakeConsole.group('group'); - fakeConsole.groupCollapsed('groupCollapsed'); + console.log('log'); + console.warn('warn'); + console.error('error'); return
; } @@ -539,77 +383,38 @@ describe('console', () => { , ), ); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockLog.mock.calls[1]).toEqual([ + + expect(global.consoleLogMock).toHaveBeenCalledTimes(2); + expect(global.consoleLogMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log', ]); - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockWarn.mock.calls[1]).toHaveLength(2); - expect(mockWarn.mock.calls[1]).toEqual([ + expect(global.consoleWarnMock).toHaveBeenCalledTimes(2); + expect(global.consoleWarnMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn', ]); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[1]).toHaveLength(2); - expect(mockError.mock.calls[1]).toEqual([ + expect(global.consoleErrorMock).toHaveBeenCalledTimes(2); + expect(global.consoleErrorMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error', ]); - - expect(mockInfo).toHaveBeenCalledTimes(2); - expect(mockInfo.mock.calls[0]).toHaveLength(1); - expect(mockInfo.mock.calls[0][0]).toBe('info'); - expect(mockInfo.mock.calls[1]).toHaveLength(2); - expect(mockInfo.mock.calls[1]).toEqual([ - '\x1b[2;38;2;124;124;124m%s\x1b[0m', - 'info', - ]); - - expect(mockGroup).toHaveBeenCalledTimes(2); - expect(mockGroup.mock.calls[0]).toHaveLength(1); - expect(mockGroup.mock.calls[0][0]).toBe('group'); - expect(mockGroup.mock.calls[1]).toHaveLength(2); - expect(mockGroup.mock.calls[1]).toEqual([ - '\x1b[2;38;2;124;124;124m%s\x1b[0m', - 'group', - ]); - - expect(mockGroupCollapsed).toHaveBeenCalledTimes(2); - expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); - expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); - expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(2); - expect(mockGroupCollapsed.mock.calls[1]).toEqual([ - '\x1b[2;38;2;124;124;124m%s\x1b[0m', - 'groupCollapsed', - ]); }); it('should not double log if hideConsoleLogsInStrictMode is enabled in Strict mode', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + true; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { - console.log( - 'CALL', - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__, - ); - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); - fakeConsole.info('info'); - fakeConsole.group('group'); - fakeConsole.groupCollapsed('groupCollapsed'); + console.log('log'); + console.warn('warn'); + console.error('error'); return
; } @@ -621,54 +426,29 @@ describe('console', () => { ), ); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - - expect(mockInfo).toHaveBeenCalledTimes(1); - expect(mockInfo.mock.calls[0]).toHaveLength(1); - expect(mockInfo.mock.calls[0][0]).toBe('info'); - - expect(mockGroup).toHaveBeenCalledTimes(1); - expect(mockGroup.mock.calls[0]).toHaveLength(1); - expect(mockGroup.mock.calls[0][0]).toBe('group'); - - expect(mockGroupCollapsed).toHaveBeenCalledTimes(1); - expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); - expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); + expect(global.consoleLogMock).toHaveBeenCalledTimes(1); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(1); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(1); }); it('should double log from Effects if hideConsoleLogsInStrictMode is disabled in Strict mode', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { React.useEffect(() => { - fakeConsole.log('log effect create'); - fakeConsole.warn('warn effect create'); - fakeConsole.error('error effect create'); - fakeConsole.info('info effect create'); - fakeConsole.group('group effect create'); - fakeConsole.groupCollapsed('groupCollapsed effect create'); + console.log('log effect create'); + console.warn('warn effect create'); + console.error('error effect create'); return () => { - fakeConsole.log('log effect cleanup'); - fakeConsole.warn('warn effect cleanup'); - fakeConsole.error('error effect cleanup'); - fakeConsole.info('info effect cleanup'); - fakeConsole.group('group effect cleanup'); - fakeConsole.groupCollapsed('groupCollapsed effect cleanup'); + console.log('log effect cleanup'); + console.warn('warn effect cleanup'); + console.error('error effect cleanup'); }; }); @@ -682,61 +462,41 @@ describe('console', () => { , ), ); - expect(mockLog.mock.calls).toEqual([ + expect(global.consoleLogMock.mock.calls).toEqual([ ['log effect create'], ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log effect cleanup'], ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log effect create'], ]); - expect(mockWarn.mock.calls).toEqual([ + expect(global.consoleWarnMock.mock.calls).toEqual([ ['warn effect create'], ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn effect cleanup'], ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn effect create'], ]); - expect(mockError.mock.calls).toEqual([ + expect(global.consoleErrorMock.mock.calls).toEqual([ ['error effect create'], ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error effect cleanup'], ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error effect create'], ]); - expect(mockInfo.mock.calls).toEqual([ - ['info effect create'], - ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info effect cleanup'], - ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'info effect create'], - ]); - expect(mockGroup.mock.calls).toEqual([ - ['group effect create'], - ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group effect cleanup'], - ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'group effect create'], - ]); - expect(mockGroupCollapsed.mock.calls).toEqual([ - ['groupCollapsed effect create'], - ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed effect cleanup'], - ['\x1b[2;38;2;124;124;124m%s\x1b[0m', 'groupCollapsed effect create'], - ]); }); it('should not double log from Effects if hideConsoleLogsInStrictMode is enabled in Strict mode', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + true; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { React.useEffect(() => { - fakeConsole.log('log effect create'); - fakeConsole.warn('warn effect create'); - fakeConsole.error('error effect create'); - fakeConsole.info('info effect create'); - fakeConsole.group('group effect create'); - fakeConsole.groupCollapsed('groupCollapsed effect create'); + console.log('log effect create'); + console.warn('warn effect create'); + console.error('error effect create'); return () => { - fakeConsole.log('log effect cleanup'); - fakeConsole.warn('warn effect cleanup'); - fakeConsole.error('error effect cleanup'); - fakeConsole.info('info effect cleanup'); - fakeConsole.group('group effect cleanup'); - fakeConsole.groupCollapsed('groupCollapsed effect cleanup'); + console.log('log effect cleanup'); + console.warn('warn effect cleanup'); + console.error('error effect cleanup'); }; }); @@ -750,31 +510,25 @@ describe('console', () => { , ), ); - expect(mockLog.mock.calls).toEqual([['log effect create']]); - expect(mockWarn.mock.calls).toEqual([['warn effect create']]); - expect(mockError.mock.calls).toEqual([['error effect create']]); - expect(mockInfo.mock.calls).toEqual([['info effect create']]); - expect(mockGroup.mock.calls).toEqual([['group effect create']]); - expect(mockGroupCollapsed.mock.calls).toEqual([ - ['groupCollapsed effect create'], - ]); + + expect(global.consoleLogMock).toHaveBeenCalledTimes(1); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(1); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(1); }); it('should double log from useMemo if hideConsoleLogsInStrictMode is disabled in Strict mode', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { React.useMemo(() => { - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); - fakeConsole.info('info'); - fakeConsole.group('group'); - fakeConsole.groupCollapsed('groupCollapsed'); + console.log('log'); + console.warn('warn'); + console.error('error'); }, []); return
; } @@ -786,78 +540,39 @@ describe('console', () => { , ), ); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockLog.mock.calls[1]).toEqual([ + + expect(global.consoleLogMock).toHaveBeenCalledTimes(2); + expect(global.consoleLogMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log', ]); - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockWarn.mock.calls[1]).toHaveLength(2); - expect(mockWarn.mock.calls[1]).toEqual([ + expect(global.consoleWarnMock).toHaveBeenCalledTimes(2); + expect(global.consoleWarnMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn', ]); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[1]).toHaveLength(2); - expect(mockError.mock.calls[1]).toEqual([ + expect(global.consoleErrorMock).toHaveBeenCalledTimes(2); + expect(global.consoleErrorMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error', ]); - - expect(mockInfo).toHaveBeenCalledTimes(2); - expect(mockInfo.mock.calls[0]).toHaveLength(1); - expect(mockInfo.mock.calls[0][0]).toBe('info'); - expect(mockInfo.mock.calls[1]).toHaveLength(2); - expect(mockInfo.mock.calls[1]).toEqual([ - '\x1b[2;38;2;124;124;124m%s\x1b[0m', - 'info', - ]); - - expect(mockGroup).toHaveBeenCalledTimes(2); - expect(mockGroup.mock.calls[0]).toHaveLength(1); - expect(mockGroup.mock.calls[0][0]).toBe('group'); - expect(mockGroup.mock.calls[1]).toHaveLength(2); - expect(mockGroup.mock.calls[1]).toEqual([ - '\x1b[2;38;2;124;124;124m%s\x1b[0m', - 'group', - ]); - - expect(mockGroupCollapsed).toHaveBeenCalledTimes(2); - expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); - expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); - expect(mockGroupCollapsed.mock.calls[1]).toHaveLength(2); - expect(mockGroupCollapsed.mock.calls[1]).toEqual([ - '\x1b[2;38;2;124;124;124m%s\x1b[0m', - 'groupCollapsed', - ]); }); it('should not double log from useMemo fns if hideConsoleLogsInStrictMode is enabled in Strict mode', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + true; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { React.useMemo(() => { - console.log( - 'CALL', - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__, - ); - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); - fakeConsole.info('info'); - fakeConsole.group('group'); - fakeConsole.groupCollapsed('groupCollapsed'); + console.log('log'); + console.warn('warn'); + console.error('error'); }, []); return
; } @@ -870,49 +585,27 @@ describe('console', () => { ), ); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - - expect(mockInfo).toHaveBeenCalledTimes(1); - expect(mockInfo.mock.calls[0]).toHaveLength(1); - expect(mockInfo.mock.calls[0][0]).toBe('info'); - - expect(mockGroup).toHaveBeenCalledTimes(1); - expect(mockGroup.mock.calls[0]).toHaveLength(1); - expect(mockGroup.mock.calls[0][0]).toBe('group'); - - expect(mockGroupCollapsed).toHaveBeenCalledTimes(1); - expect(mockGroupCollapsed.mock.calls[0]).toHaveLength(1); - expect(mockGroupCollapsed.mock.calls[0][0]).toBe('groupCollapsed'); + expect(global.consoleLogMock).toHaveBeenCalledTimes(1); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(1); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(1); }); it('should double log in Strict mode initial render for extension', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; // This simulates a render that happens before React DevTools have finished // their handshake to attach the React DOM renderer functions to DevTools // In this case, we should still be able to mock the console in Strict mode - global.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.set( - rendererID, - null, - ); + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.delete(rendererID); const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); + console.log('log'); + console.warn('warn'); + console.error('error'); return
; } @@ -924,52 +617,41 @@ describe('console', () => { ), ); - expect(mockLog).toHaveBeenCalledTimes(2); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockLog.mock.calls[1]).toHaveLength(2); - expect(mockLog.mock.calls[1]).toEqual([ + expect(global.consoleLogMock).toHaveBeenCalledTimes(2); + expect(global.consoleLogMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'log', ]); - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - expect(mockWarn.mock.calls[1]).toHaveLength(2); - expect(mockWarn.mock.calls[1]).toEqual([ + expect(global.consoleWarnMock).toHaveBeenCalledTimes(2); + expect(global.consoleWarnMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'warn', ]); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(mockError.mock.calls[1]).toHaveLength(2); - expect(mockError.mock.calls[1]).toEqual([ + expect(global.consoleErrorMock).toHaveBeenCalledTimes(2); + expect(global.consoleErrorMock.mock.calls[1]).toEqual([ '\x1b[2;38;2;124;124;124m%s\x1b[0m', 'error', ]); }); it('should not double log in Strict mode initial render for extension', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + true; // This simulates a render that happens before React DevTools have finished // their handshake to attach the React DOM renderer functions to DevTools // In this case, we should still be able to mock the console in Strict mode - global.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.set( - rendererID, - null, - ); + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces.delete(rendererID); const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); function App() { - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); + console.log('log'); + console.warn('warn'); + console.error('error'); return
; } @@ -980,22 +662,16 @@ describe('console', () => { , ), ); - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(1); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(1); - expect(mockError.mock.calls[0][0]).toBe('error'); + expect(global.consoleLogMock).toHaveBeenCalledTimes(1); + expect(global.consoleWarnMock).toHaveBeenCalledTimes(1); + expect(global.consoleErrorMock).toHaveBeenCalledTimes(1); }); it('should properly dim component stacks during strict mode double log', () => { - global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true; - global.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = false; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.appendComponentStack = true; + global.__REACT_DEVTOOLS_GLOBAL_HOOK__.settings.hideConsoleLogsInStrictMode = + false; const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); @@ -1007,8 +683,8 @@ describe('console', () => { ); const Child = ({children}) => { - fakeConsole.error('error'); - fakeConsole.warn('warn'); + console.error('error'); + console.warn('warn'); return null; }; @@ -1020,140 +696,41 @@ describe('console', () => { ), ); - expect(mockWarn).toHaveBeenCalledTimes(2); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[0][1])).toEqual( + expect( + global.consoleWarnMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'warn', supportsOwnerStacks ? '\n in Child (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockWarn.mock.calls[1]).toHaveLength(3); - expect(mockWarn.mock.calls[1][0]).toEqual( + ]); + + expect( + global.consoleWarnMock.mock.calls[1].map(normalizeCodeLocInfo), + ).toEqual([ '\x1b[2;38;2;124;124;124m%s %o\x1b[0m', - ); - expect(mockWarn.mock.calls[1][1]).toMatch('warn'); - expect(normalizeCodeLocInfo(mockWarn.mock.calls[1][2]).trim()).toEqual( + 'warn', supportsOwnerStacks - ? 'in Object.overrideMethod (at **)' + // TODO: This leading frame is due to our extra wrapper that shouldn't exist. - '\n in Child (at **)\n in Parent (at **)' + ? '\n in Child (at **)\n in Parent (at **)' : 'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); + ]); - expect(mockError).toHaveBeenCalledTimes(2); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toEqual( + expect( + global.consoleErrorMock.mock.calls[0].map(normalizeCodeLocInfo), + ).toEqual([ + 'error', supportsOwnerStacks ? '\n in Child (at **)\n in Parent (at **)' : '\n in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - expect(mockError.mock.calls[1]).toHaveLength(3); - expect(mockError.mock.calls[1][0]).toEqual( + ]); + expect( + global.consoleErrorMock.mock.calls[1].map(normalizeCodeLocInfo), + ).toEqual([ '\x1b[2;38;2;124;124;124m%s %o\x1b[0m', - ); - expect(mockError.mock.calls[1][1]).toEqual('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[1][2]).trim()).toEqual( + 'error', supportsOwnerStacks - ? 'in Object.overrideMethod (at **)' + // TODO: This leading frame is due to our extra wrapper that shouldn't exist. - '\n in Child (at **)\n in Parent (at **)' + ? '\n in Child (at **)\n in Parent (at **)' : 'in Child (at **)\n in Intermediate (at **)\n in Parent (at **)', - ); - }); -}); - -describe('console error', () => { - beforeEach(() => { - jest.resetModules(); - - const Console = require('react-devtools-shared/src/backend/console'); - patchConsole = Console.patch; - unpatchConsole = Console.unpatch; - - // Patch a fake console so we can verify with tests below. - // Patching the real console is too complicated, - // because Jest itself has hooks into it as does our test env setup. - mockError = jest.fn(); - mockInfo = jest.fn(); - mockGroup = jest.fn(); - mockGroupCollapsed = jest.fn(); - mockLog = jest.fn(); - mockWarn = jest.fn(); - fakeConsole = { - error: mockError, - info: mockInfo, - log: mockLog, - warn: mockWarn, - group: mockGroup, - groupCollapsed: mockGroupCollapsed, - }; - - Console.dangerous_setTargetConsoleForTesting(fakeConsole); - - const inject = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject; - global.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = internals => { - inject(internals); - - Console.registerRenderer( - () => { - throw Error('foo'); - }, - () => { - return { - enableOwnerStacks: true, - componentStack: '\n at FakeStack (fake-file)', - }; - }, - ); - }; - - React = require('react'); - ReactDOMClient = require('react-dom/client'); - - const utils = require('./utils'); - act = utils.act; - }); - - // @reactVersion >=18.0 - it('error in console log throws without interfering with logging', () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - - function App() { - fakeConsole.log('log'); - fakeConsole.warn('warn'); - fakeConsole.error('error'); - return
; - } - - patchConsole({ - appendComponentStack: true, - breakOnConsoleErrors: false, - showInlineWarningsAndErrors: true, - hideConsoleLogsInStrictMode: false, - }); - - expect(() => { - act(() => { - root.render(); - }); - }).toThrowError('foo'); - - expect(mockLog).toHaveBeenCalledTimes(1); - expect(mockLog.mock.calls[0]).toHaveLength(1); - expect(mockLog.mock.calls[0][0]).toBe('log'); - - expect(mockWarn).toHaveBeenCalledTimes(1); - expect(mockWarn.mock.calls[0]).toHaveLength(2); - expect(mockWarn.mock.calls[0][0]).toBe('warn'); - // An error in showInlineWarningsAndErrors doesn't need to break component stacks. - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( - '\n in FakeStack (at **)', - ); - - expect(mockError).toHaveBeenCalledTimes(1); - expect(mockError.mock.calls[0]).toHaveLength(2); - expect(mockError.mock.calls[0][0]).toBe('error'); - expect(normalizeCodeLocInfo(mockError.mock.calls[0][1])).toBe( - '\n in FakeStack (at **)', - ); + ]); }); }); diff --git a/packages/react-devtools-shared/src/__tests__/setupTests.js b/packages/react-devtools-shared/src/__tests__/setupTests.js index 79cda67f99b18..d4afd05899a56 100644 --- a/packages/react-devtools-shared/src/__tests__/setupTests.js +++ b/packages/react-devtools-shared/src/__tests__/setupTests.js @@ -13,6 +13,7 @@ import type { BackendBridge, FrontendBridge, } from 'react-devtools-shared/src/bridge'; + const {getTestFlags} = require('../../../../scripts/jest/TestFlags'); // Argument is serialized when passed from jest-cli script through to setupTests. @@ -103,61 +104,36 @@ global.gate = fn => { return fn(flags); }; -beforeEach(() => { - global.mockClipboardCopy = jest.fn(); - - // Test environment doesn't support document methods like execCommand() - // Also once the backend components below have been required, - // it's too late for a test to mock the clipboard-js modules. - jest.mock('clipboard-js', () => ({copy: global.mockClipboardCopy})); - - // These files should be required (and re-required) before each test, - // rather than imported at the head of the module. - // That's because we reset modules between tests, - // which disconnects the DevTool's cache from the current dispatcher ref. - const Agent = require('react-devtools-shared/src/backend/agent').default; - const {initBackend} = require('react-devtools-shared/src/backend'); - const Bridge = require('react-devtools-shared/src/bridge').default; - const Store = require('react-devtools-shared/src/devtools/store').default; - const {installHook} = require('react-devtools-shared/src/hook'); - const { - getDefaultComponentFilters, - setSavedComponentFilters, - } = require('react-devtools-shared/src/utils'); +function shouldIgnoreConsoleErrorOrWarn(args) { + let firstArg = args[0]; + if ( + firstArg !== null && + typeof firstArg === 'object' && + String(firstArg).indexOf('Error: Uncaught [') === 0 + ) { + firstArg = String(firstArg); + } else if (typeof firstArg !== 'string') { + return false; + } - // Fake timers let us flush Bridge operations between setup and assertions. - jest.useFakeTimers(); + return global._ignoredErrorOrWarningMessages.some(errorOrWarningMessage => { + return firstArg.indexOf(errorOrWarningMessage) !== -1; + }); +} - // We use fake timers heavily in tests but the bridge batching now uses microtasks. - global.devtoolsJestTestScheduler = callback => { - setTimeout(callback, 0); - }; +function patchConsoleForTestingBeforeHookInstallation() { + const originalConsoleError = console.error; + const originalConsoleWarn = console.warn; + const originalConsoleLog = console.log; - // Use utils.js#withErrorsOrWarningsIgnored instead of directly mutating this array. - global._ignoredErrorOrWarningMessages = [ - 'react-test-renderer is deprecated.', - ]; - function shouldIgnoreConsoleErrorOrWarn(args) { - let firstArg = args[0]; - if ( - firstArg !== null && - typeof firstArg === 'object' && - String(firstArg).indexOf('Error: Uncaught [') === 0 - ) { - firstArg = String(firstArg); - } else if (typeof firstArg !== 'string') { - return false; - } - const shouldFilter = global._ignoredErrorOrWarningMessages.some( - errorOrWarningMessage => { - return firstArg.indexOf(errorOrWarningMessage) !== -1; - }, - ); + const consoleErrorMock = jest.fn(); + const consoleWarnMock = jest.fn(); + const consoleLogMock = jest.fn(); - return shouldFilter; - } + global.consoleErrorMock = consoleErrorMock; + global.consoleWarnMock = consoleWarnMock; + global.consoleLogMock = consoleLogMock; - const originalConsoleError = console.error; console.error = (...args) => { let firstArg = args[0]; if (typeof firstArg === 'string' && firstArg.startsWith('Warning: ')) { @@ -184,17 +160,68 @@ beforeEach(() => { // Errors can be ignored by running in a special context provided by utils.js#withErrorsOrWarningsIgnored return; } + + consoleErrorMock(...args); originalConsoleError.apply(console, args); }; - const originalConsoleWarn = console.warn; console.warn = (...args) => { if (shouldIgnoreConsoleErrorOrWarn(args)) { // Allows testing how DevTools behaves when it encounters console.warn without cluttering the test output. // Warnings can be ignored by running in a special context provided by utils.js#withErrorsOrWarningsIgnored return; } + + consoleWarnMock(...args); originalConsoleWarn.apply(console, args); }; + console.log = (...args) => { + consoleLogMock(...args); + originalConsoleLog.apply(console, args); + }; +} + +function unpatchConsoleAfterTesting() { + delete global.consoleErrorMock; + delete global.consoleWarnMock; + delete global.consoleLogMock; +} + +beforeEach(() => { + patchConsoleForTestingBeforeHookInstallation(); + + global.mockClipboardCopy = jest.fn(); + + // Test environment doesn't support document methods like execCommand() + // Also once the backend components below have been required, + // it's too late for a test to mock the clipboard-js modules. + jest.mock('clipboard-js', () => ({copy: global.mockClipboardCopy})); + + // These files should be required (and re-required) before each test, + // rather than imported at the head of the module. + // That's because we reset modules between tests, + // which disconnects the DevTool's cache from the current dispatcher ref. + const Agent = require('react-devtools-shared/src/backend/agent').default; + const {initBackend} = require('react-devtools-shared/src/backend'); + const Bridge = require('react-devtools-shared/src/bridge').default; + const Store = require('react-devtools-shared/src/devtools/store').default; + const {installHook} = require('react-devtools-shared/src/hook'); + const { + getDefaultComponentFilters, + setSavedComponentFilters, + } = require('react-devtools-shared/src/utils'); + + // Fake timers let us flush Bridge operations between setup and assertions. + jest.useFakeTimers(); + + // We use fake timers heavily in tests but the bridge batching now uses microtasks. + global.devtoolsJestTestScheduler = callback => { + setTimeout(callback, 0); + }; + + // Use utils.js#withErrorsOrWarningsIgnored instead of directly mutating this array. + global._ignoredErrorOrWarningMessages = [ + 'react-test-renderer is deprecated.', + ]; // Initialize filters to a known good state. setSavedComponentFilters(getDefaultComponentFilters()); @@ -203,7 +230,12 @@ beforeEach(() => { // Also initialize inline warnings so that we can test them. global.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = true; - installHook(global); + installHook(global, { + appendComponentStack: true, + breakOnConsoleErrors: false, + showInlineWarningsAndErrors: true, + hideConsoleLogsInStrictMode: false, + }); const bridgeListeners = []; const bridge = new Bridge({ @@ -221,14 +253,12 @@ beforeEach(() => { }, }); - const agent = new Agent(((bridge: any): BackendBridge)); + const store = new Store(((bridge: any): FrontendBridge)); + const agent = new Agent(((bridge: any): BackendBridge)); const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__; - initBackend(hook, agent, global); - const store = new Store(((bridge: any): FrontendBridge)); - global.agent = agent; global.bridge = bridge; global.store = store; @@ -243,8 +273,10 @@ beforeEach(() => { } global.fetch = mockFetch; }); + afterEach(() => { delete global.__REACT_DEVTOOLS_GLOBAL_HOOK__; + unpatchConsoleAfterTesting(); // It's important to reset modules between test runs; // Without this, ReactDOM won't re-inject itself into the new hook. diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index 8112fdcd2584b..814c6c1c40e67 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -24,7 +24,6 @@ import { initialize as setupTraceUpdates, toggleEnabled as setTraceUpdatesEnabled, } from './views/TraceUpdates'; -import {patch as patchConsole} from './console'; import {currentBridgeProtocol} from 'react-devtools-shared/src/bridge'; import type {BackendBridge} from 'react-devtools-shared/src/bridge'; @@ -36,7 +35,6 @@ import type { PathMatch, RendererID, RendererInterface, - ConsolePatchSettings, DevToolsHookSettings, } from './types'; import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types'; @@ -805,7 +803,7 @@ export default class Agent extends EventEmitter<{ }; updateConsolePatchSettings: ( - settings: $ReadOnly, + settings: $ReadOnly, ) => void = settings => { // Propagate the settings, so Backend can subscribe to it and modify hook this.emit('updateHookSettings', { @@ -814,12 +812,6 @@ export default class Agent extends EventEmitter<{ showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors, hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode, }); - - // If the frontend preferences have changed, - // or in the case of React Native- if the backend is just finding out the preferences- - // then reinstall the console overrides. - // It's safe to call `patchConsole` multiple times. - patchConsole(settings); }; updateComponentFilters: (componentFilters: Array) => void = diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js index 0b6b19626a9bb..9e61285b50fe4 100644 --- a/packages/react-devtools-shared/src/backend/console.js +++ b/packages/react-devtools-shared/src/backend/console.js @@ -7,416 +7,7 @@ * @flow */ -import type { - ConsolePatchSettings, - OnErrorOrWarning, - GetComponentStack, -} from './types'; - -import { - formatConsoleArguments, - formatWithStyles, -} from 'react-devtools-shared/src/backend/utils'; -import { - FIREFOX_CONSOLE_DIMMING_COLOR, - ANSI_STYLE_DIMMING_TEMPLATE, - ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK, -} from 'react-devtools-shared/src/constants'; -import {castBool} from '../utils'; - -const OVERRIDE_CONSOLE_METHODS = ['error', 'trace', 'warn']; - -// React's custom built component stack strings match "\s{4}in" -// Chrome's prefix matches "\s{4}at" -const PREFIX_REGEX = /\s{4}(in|at)\s{1}/; -// Firefox and Safari have no prefix ("") -// but we can fallback to looking for location info (e.g. "foo.js:12:345") -const ROW_COLUMN_NUMBER_REGEX = /:\d+:\d+(\n|$)/; - -export function isStringComponentStack(text: string): boolean { - return PREFIX_REGEX.test(text) || ROW_COLUMN_NUMBER_REGEX.test(text); -} - -const STYLE_DIRECTIVE_REGEX = /^%c/; - -// This function tells whether or not the arguments for a console -// method has been overridden by the patchForStrictMode function. -// If it has we'll need to do some special formatting of the arguments -// so the console color stays consistent -function isStrictModeOverride(args: Array): boolean { - if (__IS_FIREFOX__) { - return ( - args.length >= 2 && - STYLE_DIRECTIVE_REGEX.test(args[0]) && - args[1] === FIREFOX_CONSOLE_DIMMING_COLOR - ); - } else { - return args.length >= 2 && args[0] === ANSI_STYLE_DIMMING_TEMPLATE; - } -} - -// We add a suffix to some frames that older versions of React didn't do. -// To compare if it's equivalent we strip out the suffix to see if they're -// still equivalent. Similarly, we sometimes use [] and sometimes () so we -// strip them to for the comparison. -const frameDiffs = / \(\\)$|\@unknown\:0\:0$|\(|\)|\[|\]/gm; -function areStackTracesEqual(a: string, b: string): boolean { - return a.replace(frameDiffs, '') === b.replace(frameDiffs, ''); -} - -function restorePotentiallyModifiedArgs(args: Array): Array { - // If the arguments don't have any styles applied, then just copy - if (!isStrictModeOverride(args)) { - return args.slice(); - } - - if (__IS_FIREFOX__) { - // Filter out %c from the start of the first argument and color as a second argument - return [args[0].slice(2)].concat(args.slice(2)); - } else { - // Filter out the `\x1b...%s\x1b` template - return args.slice(1); - } -} - -const injectedRenderers: Array<{ - onErrorOrWarning: ?OnErrorOrWarning, - getComponentStack: ?GetComponentStack, -}> = []; - -let targetConsole: Object = console; -let targetConsoleMethods: {[string]: $FlowFixMe} = {}; -for (const method in console) { - // $FlowFixMe[invalid-computed-prop] - targetConsoleMethods[method] = console[method]; -} - -let unpatchFn: null | (() => void) = null; - -// Enables e.g. Jest tests to inject a mock console object. -export function dangerous_setTargetConsoleForTesting( - targetConsoleForTesting: Object, -): void { - targetConsole = targetConsoleForTesting; - - targetConsoleMethods = ({}: {[string]: $FlowFixMe}); - for (const method in targetConsole) { - // $FlowFixMe[invalid-computed-prop] - targetConsoleMethods[method] = console[method]; - } -} - -// v16 renderers should use this method to inject internals necessary to generate a component stack. -// These internals will be used if the console is patched. -// Injecting them separately allows the console to easily be patched or un-patched later (at runtime). -export function registerRenderer( - onErrorOrWarning?: OnErrorOrWarning, - getComponentStack?: GetComponentStack, -): void { - injectedRenderers.push({ - onErrorOrWarning, - getComponentStack, - }); -} - -const consoleSettingsRef: ConsolePatchSettings = { - appendComponentStack: false, - breakOnConsoleErrors: false, - showInlineWarningsAndErrors: false, - hideConsoleLogsInStrictMode: false, -}; - -// Patches console methods to append component stack for the current fiber. -// Call unpatch() to remove the injected behavior. -export function patch({ - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, -}: $ReadOnly): void { - // Settings may change after we've patched the console. - // Using a shared ref allows the patch function to read the latest values. - consoleSettingsRef.appendComponentStack = appendComponentStack; - consoleSettingsRef.breakOnConsoleErrors = breakOnConsoleErrors; - consoleSettingsRef.showInlineWarningsAndErrors = showInlineWarningsAndErrors; - consoleSettingsRef.hideConsoleLogsInStrictMode = hideConsoleLogsInStrictMode; - - if ( - appendComponentStack || - breakOnConsoleErrors || - showInlineWarningsAndErrors - ) { - if (unpatchFn !== null) { - // Don't patch twice. - return; - } - - const originalConsoleMethods: {[string]: $FlowFixMe} = {}; - - unpatchFn = () => { - for (const method in originalConsoleMethods) { - try { - targetConsole[method] = originalConsoleMethods[method]; - } catch (error) {} - } - }; - - OVERRIDE_CONSOLE_METHODS.forEach(method => { - try { - const originalMethod = (originalConsoleMethods[method] = targetConsole[ - method - ].__REACT_DEVTOOLS_ORIGINAL_METHOD__ - ? targetConsole[method].__REACT_DEVTOOLS_ORIGINAL_METHOD__ - : targetConsole[method]); - - // $FlowFixMe[missing-local-annot] - const overrideMethod = (...args) => { - let alreadyHasComponentStack = false; - if (method !== 'log' && consoleSettingsRef.appendComponentStack) { - const lastArg = args.length > 0 ? args[args.length - 1] : null; - alreadyHasComponentStack = - typeof lastArg === 'string' && isStringComponentStack(lastArg); // The last argument should be a component stack. - } - - const shouldShowInlineWarningsAndErrors = - consoleSettingsRef.showInlineWarningsAndErrors && - (method === 'error' || method === 'warn'); - - // Search for the first renderer that has a current Fiber. - // We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?) - for (let i = 0; i < injectedRenderers.length; i++) { - const renderer = injectedRenderers[i]; - const {getComponentStack, onErrorOrWarning} = renderer; - try { - if (shouldShowInlineWarningsAndErrors) { - // patch() is called by two places: (1) the hook and (2) the renderer backend. - // The backend is what implements a message queue, so it's the only one that injects onErrorOrWarning. - if (onErrorOrWarning != null) { - onErrorOrWarning( - ((method: any): 'error' | 'warn'), - // Restore and copy args before we mutate them (e.g. adding the component stack) - restorePotentiallyModifiedArgs(args), - ); - } - } - } catch (error) { - // Don't let a DevTools or React internal error interfere with logging. - setTimeout(() => { - throw error; - }, 0); - } - try { - if ( - consoleSettingsRef.appendComponentStack && - getComponentStack != null - ) { - // This needs to be directly in the wrapper so we can pop exactly one frame. - const topFrame = Error('react-stack-top-frame'); - const match = getComponentStack(topFrame); - if (match !== null) { - const {enableOwnerStacks, componentStack} = match; - // Empty string means we have a match but no component stack. - // We don't need to look in other renderers but we also don't add anything. - if (componentStack !== '') { - // Create a fake Error so that when we print it we get native source maps. Every - // browser will print the .stack property of the error and then parse it back for source - // mapping. Rather than print the internal slot. So it doesn't matter that the internal - // slot doesn't line up. - const fakeError = new Error(''); - // In Chromium, only the stack property is printed but in Firefox the : - // gets printed so to make the colon make sense, we name it so we print Stack: - // and similarly Safari leave an expandable slot. - if (__IS_CHROME__ || __IS_EDGE__) { - // Before sending the stack to Chrome DevTools for formatting, - // V8 will reconstruct this according to the template : - // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/inspector/value-mirror.cc;l=252-311;drc=bdc48d1b1312cc40c00282efb1c9c5f41dcdca9a - // It has to start with ^[\w.]*Error\b to trigger stack formatting. - fakeError.name = enableOwnerStacks - ? 'Error Stack' - : 'Error Component Stack'; // This gets printed - } else { - fakeError.name = enableOwnerStacks - ? 'Stack' - : 'Component Stack'; // This gets printed - } - // In Chromium, the stack property needs to start with ^[\w.]*Error\b to trigger stack - // formatting. Otherwise it is left alone. So we prefix it. Otherwise we just override it - // to our own stack. - fakeError.stack = - __IS_CHROME__ || __IS_EDGE__ || __IS_NATIVE__ - ? (enableOwnerStacks - ? 'Error Stack:' - : 'Error Component Stack:') + componentStack - : componentStack; - - if (alreadyHasComponentStack) { - // Only modify the component stack if it matches what we would've added anyway. - // Otherwise we assume it was a non-React stack. - if (isStrictModeOverride(args)) { - // We do nothing to Strict Mode overrides that already has a stack - // because we have already lost some context for how to format it - // since we've already merged the stack into the log at this point. - } else if ( - areStackTracesEqual( - args[args.length - 1], - componentStack, - ) - ) { - const firstArg = args[0]; - if ( - args.length > 1 && - typeof firstArg === 'string' && - firstArg.endsWith('%s') - ) { - args[0] = firstArg.slice(0, firstArg.length - 2); // Strip the %s param - } - args[args.length - 1] = fakeError; - } - } else { - args.push(fakeError); - if (isStrictModeOverride(args)) { - if (__IS_FIREFOX__) { - args[0] = `${args[0]} %o`; - } else { - args[0] = - ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK; - } - } - } - } - // Don't add stacks from other renderers. - break; - } - } - } catch (error) { - // Don't let a DevTools or React internal error interfere with logging. - setTimeout(() => { - throw error; - }, 0); - } - } - - if (consoleSettingsRef.breakOnConsoleErrors) { - // --- Welcome to debugging with React DevTools --- - // This debugger statement means that you've enabled the "break on warnings" feature. - // Use the browser's Call Stack panel to step out of this override function- - // to where the original warning or error was logged. - // eslint-disable-next-line no-debugger - debugger; - } - - originalMethod(...args); - }; - - overrideMethod.__REACT_DEVTOOLS_ORIGINAL_METHOD__ = originalMethod; - originalMethod.__REACT_DEVTOOLS_OVERRIDE_METHOD__ = overrideMethod; - - targetConsole[method] = overrideMethod; - } catch (error) {} - }); - } else { - unpatch(); - } -} - -// Removed component stack patch from console methods. -export function unpatch(): void { - if (unpatchFn !== null) { - unpatchFn(); - unpatchFn = null; - } -} - -let unpatchForStrictModeFn: null | (() => void) = null; - -// NOTE: KEEP IN SYNC with src/hook.js:patchConsoleForInitialCommitInStrictMode -export function patchForStrictMode() { - const overrideConsoleMethods = [ - 'error', - 'group', - 'groupCollapsed', - 'info', - 'log', - 'trace', - 'warn', - ]; - - if (unpatchForStrictModeFn !== null) { - // Don't patch twice. - return; - } - - const originalConsoleMethods: {[string]: $FlowFixMe} = {}; - - unpatchForStrictModeFn = () => { - for (const method in originalConsoleMethods) { - try { - targetConsole[method] = originalConsoleMethods[method]; - } catch (error) {} - } - }; - - overrideConsoleMethods.forEach(method => { - try { - const originalMethod = (originalConsoleMethods[method] = targetConsole[ - method - ].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ - ? targetConsole[method].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ - : targetConsole[method]); - - // $FlowFixMe[missing-local-annot] - const overrideMethod = (...args) => { - if (!consoleSettingsRef.hideConsoleLogsInStrictMode) { - // Dim the text color of the double logs if we're not hiding them. - if (__IS_FIREFOX__) { - originalMethod( - ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), - ); - } else { - originalMethod( - ANSI_STYLE_DIMMING_TEMPLATE, - ...formatConsoleArguments(...args), - ); - } - } - }; - - overrideMethod.__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ = - originalMethod; - originalMethod.__REACT_DEVTOOLS_STRICT_MODE_OVERRIDE_METHOD__ = - overrideMethod; - - targetConsole[method] = overrideMethod; - } catch (error) {} - }); -} - -// NOTE: KEEP IN SYNC with src/hook.js:unpatchConsoleForInitialCommitInStrictMode -export function unpatchForStrictMode(): void { - if (unpatchForStrictModeFn !== null) { - unpatchForStrictModeFn(); - unpatchForStrictModeFn = null; - } -} - -export function patchConsoleUsingWindowValues() { - const appendComponentStack = - castBool(window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__) ?? true; - const breakOnConsoleErrors = - castBool(window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__) ?? false; - const showInlineWarningsAndErrors = - castBool(window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__) ?? true; - const hideConsoleLogsInStrictMode = - castBool(window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__) ?? - false; - - patch({ - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - }); -} +import type {ConsolePatchSettings} from './types'; // After receiving cached console patch settings from React Native, we set them on window. // When the console is initially patched (in renderer.js and hook.js), these values are read. @@ -433,10 +24,3 @@ export function writeConsolePatchSettingsToWindow( window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = settings.hideConsoleLogsInStrictMode; } - -export function installConsoleFunctionsToWindow(): void { - window.__REACT_DEVTOOLS_CONSOLE_FUNCTIONS__ = { - patchConsoleUsingWindowValues, - registerRendererWithConsole: registerRenderer, - }; -} diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 2fd768b5d01c3..b8636c557ea25 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -71,12 +71,6 @@ import { TREE_OPERATION_UPDATE_TREE_BASE_DURATION, } from '../../constants'; import {inspectHooksOfFiber} from 'react-debug-tools'; -import { - patchConsoleUsingWindowValues, - registerRenderer as registerRendererWithConsole, - patchForStrictMode as patchConsoleForStrictMode, - unpatchForStrictMode as unpatchConsoleForStrictMode, -} from '../console'; import { CONCURRENT_MODE_NUMBER, CONCURRENT_MODE_SYMBOL_STRING, @@ -1198,16 +1192,6 @@ export function attach( needsToFlushComponentLogs = true; } - // Patching the console enables DevTools to do a few useful things: - // * Append component stacks to warnings and error messages - // * Disable logging during re-renders to inspect hooks (see inspectHooksOfFiber) - registerRendererWithConsole(onErrorOrWarning, getComponentStack); - - // The renderer interface can't read these preferences directly, - // because it is stored in localStorage within the context of the extension. - // It relies on the extension to pass the preference through via the global. - patchConsoleUsingWindowValues(); - function debug( name: string, instance: DevToolsInstance, @@ -5788,7 +5772,6 @@ export function attach( hasElementWithId, inspectElement, logElementToConsole, - patchConsoleForStrictMode, getComponentStack, getElementAttributeByPath, getElementSourceFunctionById, @@ -5803,7 +5786,6 @@ export function attach( startProfiling, stopProfiling, storeAsGlobal, - unpatchConsoleForStrictMode, updateComponentFilters, getEnvironmentNames, }; diff --git a/packages/react-devtools-shared/src/backend/flight/renderer.js b/packages/react-devtools-shared/src/backend/flight/renderer.js index 065dc81a071a7..3d8befd4215e7 100644 --- a/packages/react-devtools-shared/src/backend/flight/renderer.js +++ b/packages/react-devtools-shared/src/backend/flight/renderer.js @@ -19,11 +19,6 @@ import {componentInfoToComponentLogsMap} from '../shared/DevToolsServerComponent import {formatConsoleArgumentsToSingleString} from 'react-devtools-shared/src/backend/utils'; -import { - patchConsoleUsingWindowValues, - registerRenderer as registerRendererWithConsole, -} from '../console'; - function supportsConsoleTasks(componentInfo: ReactComponentInfo): boolean { // If this ReactComponentInfo supports native console.createTask then we are already running // inside a native async stack trace if it's active - meaning the DevTools is open. @@ -145,9 +140,6 @@ export function attach( // The changes will be flushed later when we commit this tree to Fiber. } - patchConsoleUsingWindowValues(); - registerRendererWithConsole(onErrorOrWarning, getComponentStack); - return { cleanup() {}, clearErrorsAndWarnings() {}, @@ -205,7 +197,6 @@ export function attach( }; }, logElementToConsole() {}, - patchConsoleForStrictMode() {}, getElementAttributeByPath() {}, getElementSourceFunctionById() {}, onErrorOrWarning, @@ -219,7 +210,6 @@ export function attach( startProfiling() {}, stopProfiling() {}, storeAsGlobal() {}, - unpatchConsoleForStrictMode() {}, updateComponentFilters() {}, getEnvironmentNames() { return []; diff --git a/packages/react-devtools-shared/src/backend/legacy/renderer.js b/packages/react-devtools-shared/src/backend/legacy/renderer.js index 828d05fc27f81..8e26dcae445ee 100644 --- a/packages/react-devtools-shared/src/backend/legacy/renderer.js +++ b/packages/react-devtools-shared/src/backend/legacy/renderer.js @@ -1103,10 +1103,6 @@ export function attach( // Not implemented } - function patchConsoleForStrictMode() {} - - function unpatchConsoleForStrictMode() {} - function hasElementWithId(id: number): boolean { return idToInternalInstanceMap.has(id); } @@ -1141,7 +1137,6 @@ export function attach( overrideSuspense, overrideValueAtPath, renamePath, - patchConsoleForStrictMode, getElementAttributeByPath, getElementSourceFunctionById, renderer, @@ -1150,7 +1145,6 @@ export function attach( startProfiling, stopProfiling, storeAsGlobal, - unpatchConsoleForStrictMode, updateComponentFilters, getEnvironmentNames, }; diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index fa9949e3ddc5d..bdc93a19baa8b 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -404,7 +404,6 @@ export type RendererInterface = { path: Array, value: any, ) => void, - patchConsoleForStrictMode: () => void, getElementAttributeByPath: ( id: number, path: Array, @@ -427,7 +426,6 @@ export type RendererInterface = { path: Array, count: number, ) => void, - unpatchConsoleForStrictMode: () => void, updateComponentFilters: (componentFilters: Array) => void, getEnvironmentNames: () => Array, diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index 65a52b571a680..156319b366d71 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -15,7 +15,7 @@ import type { OwnersList, ProfilingDataBackend, RendererID, - ConsolePatchSettings, + DevToolsHookSettings, } from 'react-devtools-shared/src/backend/types'; import type {StyleAndLayout as StyleAndLayoutPayload} from 'react-devtools-shared/src/backend/NativeStyleEditor/types'; @@ -241,7 +241,7 @@ type FrontendEvents = { storeAsGlobal: [StoreAsGlobalParams], updateComponentFilters: [Array], getEnvironmentNames: [], - updateConsolePatchSettings: [ConsolePatchSettings], + updateConsolePatchSettings: [DevToolsHookSettings], viewAttributeSource: [ViewAttributeSourceParams], viewElementSource: [ElementAndRendererID], diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 1dd1fcbd4c455..ac56d13d6ab4e 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -21,10 +21,31 @@ import type { import { FIREFOX_CONSOLE_DIMMING_COLOR, ANSI_STYLE_DIMMING_TEMPLATE, + ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK, } from 'react-devtools-shared/src/constants'; import attachRenderer from './attachRenderer'; -declare var window: any; +// React's custom built component stack strings match "\s{4}in" +// Chrome's prefix matches "\s{4}at" +const PREFIX_REGEX = /\s{4}(in|at)\s{1}/; +// Firefox and Safari have no prefix ("") +// but we can fallback to looking for location info (e.g. "foo.js:12:345") +const ROW_COLUMN_NUMBER_REGEX = /:\d+:\d+(\n|$)/; + +function isStringComponentStack(text: string): boolean { + return PREFIX_REGEX.test(text) || ROW_COLUMN_NUMBER_REGEX.test(text); +} + +// We add a suffix to some frames that older versions of React didn't do. +// To compare if it's equivalent we strip out the suffix to see if they're +// still equivalent. Similarly, we sometimes use [] and sometimes () so we +// strip them to for the comparison. +const frameDiffs = / \(\\)$|\@unknown\:0\:0$|\(|\)|\[|\]/gm; +function areStackTracesEqual(a: string, b: string): boolean { + return a.replace(frameDiffs, '') === b.replace(frameDiffs, ''); +} + +const targetConsole: Object = console; export function installHook( target: any, @@ -36,25 +57,6 @@ export function installHook( return null; } - let targetConsole: Object = console; - let targetConsoleMethods: {[string]: $FlowFixMe} = {}; - for (const method in console) { - // $FlowFixMe[invalid-computed-prop] - targetConsoleMethods[method] = console[method]; - } - - function dangerous_setTargetConsoleForTesting( - targetConsoleForTesting: Object, - ): void { - targetConsole = targetConsoleForTesting; - - targetConsoleMethods = ({}: {[string]: $FlowFixMe}); - for (const method in targetConsole) { - // $FlowFixMe[invalid-computed-prop] - targetConsoleMethods[method] = console[method]; - } - } - function detectReactBuildType(renderer: ReactRenderer) { try { if (typeof renderer.version === 'string') { @@ -189,10 +191,7 @@ export function installHook( } // NOTE: KEEP IN SYNC with src/backend/utils.js - function formatWithStyles( - inputArgs: $ReadOnlyArray, - style?: string, - ): $ReadOnlyArray { + function formatWithStyles(inputArgs: Array, style?: string): Array { if ( inputArgs === undefined || inputArgs === null || @@ -285,85 +284,6 @@ export function installHook( return [template, ...args]; } - let unpatchFn = null; - - // NOTE: KEEP IN SYNC with src/backend/console.js:patchForStrictMode - // This function hides or dims console logs during the initial double renderer - // in Strict Mode. We need this function because during initial render, - // React and DevTools are connecting and the renderer interface isn't avaiable - // and we want to be able to have consistent logging behavior for double logs - // during the initial renderer. - function patchConsoleForInitialCommitInStrictMode( - hideConsoleLogsInStrictMode: boolean, - ) { - const overrideConsoleMethods = [ - 'error', - 'group', - 'groupCollapsed', - 'info', - 'log', - 'trace', - 'warn', - ]; - - if (unpatchFn !== null) { - // Don't patch twice. - return; - } - - const originalConsoleMethods: {[string]: $FlowFixMe} = {}; - - unpatchFn = () => { - for (const method in originalConsoleMethods) { - try { - targetConsole[method] = originalConsoleMethods[method]; - } catch (error) {} - } - }; - - overrideConsoleMethods.forEach(method => { - try { - const originalMethod = (originalConsoleMethods[method] = targetConsole[ - method - ].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ - ? targetConsole[method].__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ - : targetConsole[method]); - - const overrideMethod = (...args: $ReadOnlyArray) => { - // Dim the text color of the double logs if we're not hiding them. - if (!hideConsoleLogsInStrictMode) { - // Firefox doesn't support ANSI escape sequences - if (__IS_FIREFOX__) { - originalMethod( - ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), - ); - } else { - originalMethod( - ANSI_STYLE_DIMMING_TEMPLATE, - ...formatConsoleArguments(...args), - ); - } - } - }; - - overrideMethod.__REACT_DEVTOOLS_STRICT_MODE_ORIGINAL_METHOD__ = - originalMethod; - originalMethod.__REACT_DEVTOOLS_STRICT_MODE_OVERRIDE_METHOD__ = - overrideMethod; - - targetConsole[method] = overrideMethod; - } catch (error) {} - }); - } - - // NOTE: KEEP IN SYNC with src/backend/console.js:unpatchForStrictMode - function unpatchConsoleForInitialCommitInStrictMode() { - if (unpatchFn !== null) { - unpatchFn(); - unpatchFn = null; - } - } - let uidCounter = 0; function inject(renderer: ReactRenderer): number { const id = ++uidCounter; @@ -469,28 +389,85 @@ export function installHook( } } - function setStrictMode(rendererID: RendererID, isStrictMode: any) { - const rendererInterface = rendererInterfaces.get(rendererID); - if (rendererInterface != null) { - if (isStrictMode) { - rendererInterface.patchConsoleForStrictMode(); - } else { - rendererInterface.unpatchConsoleForStrictMode(); - } + let isRunningDuringStrictModeInvocation = false; + function setStrictMode(rendererID: RendererID, isStrictMode: boolean) { + isRunningDuringStrictModeInvocation = isStrictMode; + + if (isStrictMode) { + patchConsoleForStrictMode(); } else { - // This should only happen during initial commit in the extension before DevTools - // finishes its handshake with the injected renderer - if (isStrictMode) { - const hideConsoleLogsInStrictMode = - window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ === true; - - patchConsoleForInitialCommitInStrictMode(hideConsoleLogsInStrictMode); - } else { - unpatchConsoleForInitialCommitInStrictMode(); - } + unpatchConsoleForStrictMode(); + } + } + + const unpatchConsoleCallbacks = []; + // For StrictMode we patch console once we are running in StrictMode and unpatch right after it + // So patching could happen multiple times during the runtime + // Notice how we don't patch error or warn methods, because they are already patched in patchConsoleForErrorsAndWarnings + // This will only happen once, when hook is installed + function patchConsoleForStrictMode() { + // Don't patch console in case settings were not injected + if (!hook.settings) { + return; + } + + // Don't patch twice + if (unpatchConsoleCallbacks.length > 0) { + return; + } + + // At this point 'error', 'warn', and 'trace' methods are already patched + // by React DevTools hook to append component stacks and other possible features. + const consoleMethodsToOverrideForStrictMode = [ + 'group', + 'groupCollapsed', + 'info', + 'log', + ]; + + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const method of consoleMethodsToOverrideForStrictMode) { + const originalMethod = targetConsole[method]; + const overrideMethod: (...args: Array) => void = ( + ...args: any[] + ) => { + const settings = hook.settings; + // Something unexpected happened, fallback to just printing the console message. + if (settings == null) { + originalMethod(...args); + return; + } + + if (settings.hideConsoleLogsInStrictMode) { + return; + } + + // Dim the text color of the double logs if we're not hiding them. + // Firefox doesn't support ANSI escape sequences + if (__IS_FIREFOX__) { + originalMethod( + ...formatWithStyles(args, FIREFOX_CONSOLE_DIMMING_COLOR), + ); + } else { + originalMethod( + ANSI_STYLE_DIMMING_TEMPLATE, + ...formatConsoleArguments(...args), + ); + } + }; + + targetConsole[method] = overrideMethod; + unpatchConsoleCallbacks.push(() => { + targetConsole[method] = originalMethod; + }); } } + function unpatchConsoleForStrictMode() { + unpatchConsoleCallbacks.forEach(callback => callback()); + unpatchConsoleCallbacks.length = 0; + } + type StackFrameString = string; const openModuleRangesStack: Array = []; @@ -526,6 +503,188 @@ export function installHook( } } + // For Errors and Warnings we only patch console once + function patchConsoleForErrorsAndWarnings() { + // Don't patch console in case settings were not injected + if (!hook.settings) { + return; + } + + const consoleMethodsToOverrideForErrorsAndWarnings = [ + 'error', + 'trace', + 'warn', + ]; + + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const method of consoleMethodsToOverrideForErrorsAndWarnings) { + const originalMethod = targetConsole[method]; + const overrideMethod: (...args: Array) => void = (...args) => { + const settings = hook.settings; + // Something unexpected happened, fallback to just printing the console message. + if (settings == null) { + originalMethod(...args); + return; + } + + if ( + isRunningDuringStrictModeInvocation && + settings.hideConsoleLogsInStrictMode + ) { + return; + } + + let injectedComponentStackAsFakeError = false; + let alreadyHasComponentStack = false; + if (settings.appendComponentStack) { + const lastArg = args.length > 0 ? args[args.length - 1] : null; + alreadyHasComponentStack = + typeof lastArg === 'string' && isStringComponentStack(lastArg); // The last argument should be a component stack. + } + + const shouldShowInlineWarningsAndErrors = + settings.showInlineWarningsAndErrors && + (method === 'error' || method === 'warn'); + + // Search for the first renderer that has a current Fiber. + // We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?) + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const rendererInterface of hook.rendererInterfaces.values()) { + const {onErrorOrWarning, getComponentStack} = rendererInterface; + try { + if (shouldShowInlineWarningsAndErrors) { + // patch() is called by two places: (1) the hook and (2) the renderer backend. + // The backend is what implements a message queue, so it's the only one that injects onErrorOrWarning. + if (onErrorOrWarning != null) { + onErrorOrWarning( + ((method: any): 'error' | 'warn'), + args.slice(), + ); + } + } + } catch (error) { + // Don't let a DevTools or React internal error interfere with logging. + setTimeout(() => { + throw error; + }, 0); + } + + try { + if (settings.appendComponentStack && getComponentStack != null) { + // This needs to be directly in the wrapper so we can pop exactly one frame. + const topFrame = Error('react-stack-top-frame'); + const match = getComponentStack(topFrame); + if (match !== null) { + const {enableOwnerStacks, componentStack} = match; + // Empty string means we have a match but no component stack. + // We don't need to look in other renderers but we also don't add anything. + if (componentStack !== '') { + // Create a fake Error so that when we print it we get native source maps. Every + // browser will print the .stack property of the error and then parse it back for source + // mapping. Rather than print the internal slot. So it doesn't matter that the internal + // slot doesn't line up. + const fakeError = new Error(''); + // In Chromium, only the stack property is printed but in Firefox the : + // gets printed so to make the colon make sense, we name it so we print Stack: + // and similarly Safari leave an expandable slot. + if (__IS_CHROME__ || __IS_EDGE__) { + // Before sending the stack to Chrome DevTools for formatting, + // V8 will reconstruct this according to the template : + // https://source.chromium.org/chromium/chromium/src/+/main:v8/src/inspector/value-mirror.cc;l=252-311;drc=bdc48d1b1312cc40c00282efb1c9c5f41dcdca9a + // It has to start with ^[\w.]*Error\b to trigger stack formatting. + fakeError.name = enableOwnerStacks + ? 'Error Stack' + : 'Error Component Stack'; // This gets printed + } else { + fakeError.name = enableOwnerStacks + ? 'Stack' + : 'Component Stack'; // This gets printed + } + // In Chromium, the stack property needs to start with ^[\w.]*Error\b to trigger stack + // formatting. Otherwise it is left alone. So we prefix it. Otherwise we just override it + // to our own stack. + fakeError.stack = + __IS_CHROME__ || __IS_EDGE__ || __IS_NATIVE__ + ? (enableOwnerStacks + ? 'Error Stack:' + : 'Error Component Stack:') + componentStack + : componentStack; + + if (alreadyHasComponentStack) { + // Only modify the component stack if it matches what we would've added anyway. + // Otherwise we assume it was a non-React stack. + if ( + areStackTracesEqual(args[args.length - 1], componentStack) + ) { + const firstArg = args[0]; + if ( + args.length > 1 && + typeof firstArg === 'string' && + firstArg.endsWith('%s') + ) { + args[0] = firstArg.slice(0, firstArg.length - 2); // Strip the %s param + } + args[args.length - 1] = fakeError; + injectedComponentStackAsFakeError = true; + } + } else { + args.push(fakeError); + injectedComponentStackAsFakeError = true; + } + } + + // Don't add stacks from other renderers. + break; + } + } + } catch (error) { + // Don't let a DevTools or React internal error interfere with logging. + setTimeout(() => { + throw error; + }, 0); + } + } + + if (settings.breakOnConsoleErrors) { + // --- Welcome to debugging with React DevTools --- + // This debugger statement means that you've enabled the "break on warnings" feature. + // Use the browser's Call Stack panel to step out of this override function + // to where the original warning or error was logged. + // eslint-disable-next-line no-debugger + debugger; + } + + if (isRunningDuringStrictModeInvocation) { + // Dim the text color of the double logs if we're not hiding them. + // Firefox doesn't support ANSI escape sequences + if (__IS_FIREFOX__) { + const argsWithCSSStyles = formatWithStyles( + args, + FIREFOX_CONSOLE_DIMMING_COLOR, + ); + + if (injectedComponentStackAsFakeError) { + argsWithCSSStyles[0] = `${argsWithCSSStyles[0]} %o`; + } + + originalMethod(...argsWithCSSStyles); + } else { + originalMethod( + injectedComponentStackAsFakeError + ? ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK + : ANSI_STYLE_DIMMING_TEMPLATE, + ...formatConsoleArguments(...args), + ); + } + } else { + originalMethod(...args); + } + }; + + targetConsole[method] = overrideMethod; + } + } + // TODO: More meaningful names for "rendererInterfaces" and "renderers". const fiberRoots: {[RendererID]: Set} = {}; const rendererInterfaces = new Map(); @@ -580,10 +739,12 @@ export function installHook( showInlineWarningsAndErrors: true, hideConsoleLogsInStrictMode: false, }; + patchConsoleForErrorsAndWarnings(); } else { Promise.resolve(maybeSettingsOrSettingsPromise) .then(settings => { hook.settings = settings; + patchConsoleForErrorsAndWarnings(); }) .catch(() => { targetConsole.error( @@ -592,11 +753,6 @@ export function installHook( }); } - if (__TEST__) { - hook.dangerous_setTargetConsoleForTesting = - dangerous_setTargetConsoleForTesting; - } - Object.defineProperty( target, '__REACT_DEVTOOLS_GLOBAL_HOOK__', From fce46066571e7bf3ab6ce5bfe5fd3a615e098421 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 18:16:20 +0100 Subject: [PATCH 167/426] chore[react-devtools]: extract some utils into separate modules to unify implementations (#30597) Stacked on https://github.com/facebook/react/pull/30596. See [this commit](https://github.com/facebook/react/pull/30597/commits/4ba5e784bbfdcd69021e2d84c75ffe26fcb698f4). Moving `formatWithStyles` and `formatConsoleArguments` to its own modules, so that we can finally have a single implementation for these and stop inlining them in RDT global hook object. --- .../backend/utils/formatConsoleArguments.js | 72 ++++++++++ .../src/backend/utils/formatWithStyles.js | 67 ++++++++++ .../src/backend/{utils.js => utils/index.js} | 124 +----------------- packages/react-devtools-shared/src/hook.js | 103 +-------------- 4 files changed, 150 insertions(+), 216 deletions(-) create mode 100644 packages/react-devtools-shared/src/backend/utils/formatConsoleArguments.js create mode 100644 packages/react-devtools-shared/src/backend/utils/formatWithStyles.js rename packages/react-devtools-shared/src/backend/{utils.js => utils/index.js} (72%) diff --git a/packages/react-devtools-shared/src/backend/utils/formatConsoleArguments.js b/packages/react-devtools-shared/src/backend/utils/formatConsoleArguments.js new file mode 100644 index 0000000000000..a2d303e543ac0 --- /dev/null +++ b/packages/react-devtools-shared/src/backend/utils/formatConsoleArguments.js @@ -0,0 +1,72 @@ +/** + * 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 + */ + +// Do not add / import anything to this file. +// This function could be used from multiple places, including hook. + +// Skips CSS and object arguments, inlines other in the first argument as a template string +export default function formatConsoleArguments( + maybeMessage: any, + ...inputArgs: $ReadOnlyArray +): $ReadOnlyArray { + if (inputArgs.length === 0 || typeof maybeMessage !== 'string') { + return [maybeMessage, ...inputArgs]; + } + + const args = inputArgs.slice(); + + let template = ''; + let argumentsPointer = 0; + for (let i = 0; i < maybeMessage.length; ++i) { + const currentChar = maybeMessage[i]; + if (currentChar !== '%') { + template += currentChar; + continue; + } + + const nextChar = maybeMessage[i + 1]; + ++i; + + // Only keep CSS and objects, inline other arguments + switch (nextChar) { + case 'c': + case 'O': + case 'o': { + ++argumentsPointer; + template += `%${nextChar}`; + + break; + } + case 'd': + case 'i': { + const [arg] = args.splice(argumentsPointer, 1); + template += parseInt(arg, 10).toString(); + + break; + } + case 'f': { + const [arg] = args.splice(argumentsPointer, 1); + template += parseFloat(arg).toString(); + + break; + } + case 's': { + const [arg] = args.splice(argumentsPointer, 1); + template += arg.toString(); + + break; + } + + default: + template += `%${nextChar}`; + } + } + + return [template, ...args]; +} diff --git a/packages/react-devtools-shared/src/backend/utils/formatWithStyles.js b/packages/react-devtools-shared/src/backend/utils/formatWithStyles.js new file mode 100644 index 0000000000000..b258141e353f0 --- /dev/null +++ b/packages/react-devtools-shared/src/backend/utils/formatWithStyles.js @@ -0,0 +1,67 @@ +/** + * 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 + */ + +// Do not add / import anything to this file. +// This function could be used from multiple places, including hook. + +// Formats an array of args with a style for console methods, using +// the following algorithm: +// 1. The first param is a string that contains %c +// - Bail out and return the args without modifying the styles. +// We don't want to affect styles that the developer deliberately set. +// 2. The first param is a string that doesn't contain %c but contains +// string formatting +// - [`%c${args[0]}`, style, ...args.slice(1)] +// - Note: we assume that the string formatting that the developer uses +// is correct. +// 3. The first param is a string that doesn't contain string formatting +// OR is not a string +// - Create a formatting string where: +// boolean, string, symbol -> %s +// number -> %f OR %i depending on if it's an int or float +// default -> %o +export default function formatWithStyles( + inputArgs: $ReadOnlyArray, + style?: string, +): $ReadOnlyArray { + if ( + inputArgs === undefined || + inputArgs === null || + inputArgs.length === 0 || + // Matches any of %c but not %%c + (typeof inputArgs[0] === 'string' && inputArgs[0].match(/([^%]|^)(%c)/g)) || + style === undefined + ) { + return inputArgs; + } + + // Matches any of %(o|O|d|i|s|f), but not %%(o|O|d|i|s|f) + const REGEXP = /([^%]|^)((%%)*)(%([oOdisf]))/g; + if (typeof inputArgs[0] === 'string' && inputArgs[0].match(REGEXP)) { + return [`%c${inputArgs[0]}`, style, ...inputArgs.slice(1)]; + } else { + const firstArg = inputArgs.reduce((formatStr, elem, i) => { + if (i > 0) { + formatStr += ' '; + } + switch (typeof elem) { + case 'string': + case 'boolean': + case 'symbol': + return (formatStr += '%s'); + case 'number': + const formatting = Number.isInteger(elem) ? '%i' : '%f'; + return (formatStr += formatting); + default: + return (formatStr += '%o'); + } + }, '%c'); + return [firstArg, style, ...inputArgs]; + } +} diff --git a/packages/react-devtools-shared/src/backend/utils.js b/packages/react-devtools-shared/src/backend/utils/index.js similarity index 72% rename from packages/react-devtools-shared/src/backend/utils.js rename to packages/react-devtools-shared/src/backend/utils/index.js index e763bdd759759..1e7934af9835b 100644 --- a/packages/react-devtools-shared/src/backend/utils.js +++ b/packages/react-devtools-shared/src/backend/utils/index.js @@ -9,12 +9,15 @@ */ import {compareVersions} from 'compare-versions'; -import {dehydrate} from '../hydration'; +import {dehydrate} from 'react-devtools-shared/src/hydration'; import isArray from 'shared/isArray'; import type {Source} from 'react-devtools-shared/src/shared/types'; import type {DehydratedData} from 'react-devtools-shared/src/frontend/types'; +export {default as formatWithStyles} from './formatWithStyles'; +export {default as formatConsoleArguments} from './formatConsoleArguments'; + // TODO: update this to the first React version that has a corresponding DevTools backend const FIRST_DEVTOOLS_BACKEND_LOCKSTEP_VER = '999.9.9'; export function hasAssignedBackend(version?: string): boolean { @@ -164,125 +167,6 @@ export function serializeToString(data: any): string { ); } -// NOTE: KEEP IN SYNC with src/hook.js -// Formats an array of args with a style for console methods, using -// the following algorithm: -// 1. The first param is a string that contains %c -// - Bail out and return the args without modifying the styles. -// We don't want to affect styles that the developer deliberately set. -// 2. The first param is a string that doesn't contain %c but contains -// string formatting -// - [`%c${args[0]}`, style, ...args.slice(1)] -// - Note: we assume that the string formatting that the developer uses -// is correct. -// 3. The first param is a string that doesn't contain string formatting -// OR is not a string -// - Create a formatting string where: -// boolean, string, symbol -> %s -// number -> %f OR %i depending on if it's an int or float -// default -> %o -export function formatWithStyles( - inputArgs: $ReadOnlyArray, - style?: string, -): $ReadOnlyArray { - if ( - inputArgs === undefined || - inputArgs === null || - inputArgs.length === 0 || - // Matches any of %c but not %%c - (typeof inputArgs[0] === 'string' && inputArgs[0].match(/([^%]|^)(%c)/g)) || - style === undefined - ) { - return inputArgs; - } - - // Matches any of %(o|O|d|i|s|f), but not %%(o|O|d|i|s|f) - const REGEXP = /([^%]|^)((%%)*)(%([oOdisf]))/g; - if (typeof inputArgs[0] === 'string' && inputArgs[0].match(REGEXP)) { - return [`%c${inputArgs[0]}`, style, ...inputArgs.slice(1)]; - } else { - const firstArg = inputArgs.reduce((formatStr, elem, i) => { - if (i > 0) { - formatStr += ' '; - } - switch (typeof elem) { - case 'string': - case 'boolean': - case 'symbol': - return (formatStr += '%s'); - case 'number': - const formatting = Number.isInteger(elem) ? '%i' : '%f'; - return (formatStr += formatting); - default: - return (formatStr += '%o'); - } - }, '%c'); - return [firstArg, style, ...inputArgs]; - } -} - -// NOTE: KEEP IN SYNC with src/hook.js -// Skips CSS and object arguments, inlines other in the first argument as a template string -export function formatConsoleArguments( - maybeMessage: any, - ...inputArgs: $ReadOnlyArray -): $ReadOnlyArray { - if (inputArgs.length === 0 || typeof maybeMessage !== 'string') { - return [maybeMessage, ...inputArgs]; - } - - const args = inputArgs.slice(); - - let template = ''; - let argumentsPointer = 0; - for (let i = 0; i < maybeMessage.length; ++i) { - const currentChar = maybeMessage[i]; - if (currentChar !== '%') { - template += currentChar; - continue; - } - - const nextChar = maybeMessage[i + 1]; - ++i; - - // Only keep CSS and objects, inline other arguments - switch (nextChar) { - case 'c': - case 'O': - case 'o': { - ++argumentsPointer; - template += `%${nextChar}`; - - break; - } - case 'd': - case 'i': { - const [arg] = args.splice(argumentsPointer, 1); - template += parseInt(arg, 10).toString(); - - break; - } - case 'f': { - const [arg] = args.splice(argumentsPointer, 1); - template += parseFloat(arg).toString(); - - break; - } - case 's': { - const [arg] = args.splice(argumentsPointer, 1); - template += arg.toString(); - - break; - } - - default: - template += `%${nextChar}`; - } - } - - return [template, ...args]; -} - // based on https://github.com/tmpfs/format-util/blob/0e62d430efb0a1c51448709abd3e2406c14d8401/format.js#L1 // based on https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions // Implements s, d, i and f placeholders diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index ac56d13d6ab4e..2f0698b8e1353 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -24,6 +24,8 @@ import { ANSI_STYLE_DIMMING_TEMPLATE_WITH_COMPONENT_STACK, } from 'react-devtools-shared/src/constants'; import attachRenderer from './attachRenderer'; +import formatConsoleArguments from 'react-devtools-shared/src/backend/utils/formatConsoleArguments'; +import formatWithStyles from 'react-devtools-shared/src/backend/utils/formatWithStyles'; // React's custom built component stack strings match "\s{4}in" // Chrome's prefix matches "\s{4}at" @@ -190,100 +192,6 @@ export function installHook( } catch (err) {} } - // NOTE: KEEP IN SYNC with src/backend/utils.js - function formatWithStyles(inputArgs: Array, style?: string): Array { - if ( - inputArgs === undefined || - inputArgs === null || - inputArgs.length === 0 || - // Matches any of %c but not %%c - (typeof inputArgs[0] === 'string' && - inputArgs[0].match(/([^%]|^)(%c)/g)) || - style === undefined - ) { - return inputArgs; - } - - // Matches any of %(o|O|d|i|s|f), but not %%(o|O|d|i|s|f) - const REGEXP = /([^%]|^)((%%)*)(%([oOdisf]))/g; - if (typeof inputArgs[0] === 'string' && inputArgs[0].match(REGEXP)) { - return [`%c${inputArgs[0]}`, style, ...inputArgs.slice(1)]; - } else { - const firstArg = inputArgs.reduce((formatStr, elem, i) => { - if (i > 0) { - formatStr += ' '; - } - switch (typeof elem) { - case 'string': - case 'boolean': - case 'symbol': - return (formatStr += '%s'); - case 'number': - const formatting = Number.isInteger(elem) ? '%i' : '%f'; - return (formatStr += formatting); - default: - return (formatStr += '%o'); - } - }, '%c'); - return [firstArg, style, ...inputArgs]; - } - } - // NOTE: KEEP IN SYNC with src/backend/utils.js - function formatConsoleArguments( - maybeMessage: any, - ...inputArgs: $ReadOnlyArray - ): $ReadOnlyArray { - if (inputArgs.length === 0 || typeof maybeMessage !== 'string') { - return [maybeMessage, ...inputArgs]; - } - - const args = inputArgs.slice(); - - let template = ''; - let argumentsPointer = 0; - for (let i = 0; i < maybeMessage.length; ++i) { - const currentChar = maybeMessage[i]; - if (currentChar !== '%') { - template += currentChar; - continue; - } - - const nextChar = maybeMessage[i + 1]; - ++i; - - // Only keep CSS and objects, inline other arguments - switch (nextChar) { - case 'c': - case 'O': - case 'o': { - ++argumentsPointer; - template += `%${nextChar}`; - - break; - } - case 'd': - case 'i': { - const [arg] = args.splice(argumentsPointer, 1); - template += parseInt(arg, 10).toString(); - - break; - } - case 'f': { - const [arg] = args.splice(argumentsPointer, 1); - template += parseFloat(arg).toString(); - - break; - } - case 's': { - const [arg] = args.splice(argumentsPointer, 1); - template += arg.toString(); - } - } - } - - return [template, ...args]; - } - let uidCounter = 0; function inject(renderer: ReactRenderer): number { const id = ++uidCounter; @@ -658,13 +566,16 @@ export function installHook( // Dim the text color of the double logs if we're not hiding them. // Firefox doesn't support ANSI escape sequences if (__IS_FIREFOX__) { - const argsWithCSSStyles = formatWithStyles( + let argsWithCSSStyles = formatWithStyles( args, FIREFOX_CONSOLE_DIMMING_COLOR, ); if (injectedComponentStackAsFakeError) { - argsWithCSSStyles[0] = `${argsWithCSSStyles[0]} %o`; + argsWithCSSStyles = [ + `${argsWithCSSStyles[0]} %o`, + ...argsWithCSSStyles.slice(1), + ]; } originalMethod(...argsWithCSSStyles); From e33acfd67f0003272a9aec7a0725d19a429f2460 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 18:19:01 +0100 Subject: [PATCH 168/426] refactor[react-devtools]: propagate settings from global hook object to frontend (#30610) Stacked on https://github.com/facebook/react/pull/30597 and whats under it. See [this commit](https://github.com/facebook/react/pull/30610/commits/59b4efa72377bf62f5ec8c0e32e56902cf73fbd7). With this change, the initial values for console patching settings are propagated from hook (which is the source of truth now, because of https://github.com/facebook/react/pull/30596) to the UI. Instead of reading from `localStorage` the frontend is now requesting it from the hook. This happens when settings modal is rendered, and wrapped in a transition. Also, this is happening even if settings modal is not opened yet, so we have enough time to fetch this data without displaying loader or similar UI. --- packages/react-devtools-core/src/backend.js | 4 +- .../react-devtools-core/src/cachedSettings.js | 2 +- .../src/backend/agent.js | 37 ++++++++----- .../src/backend/index.js | 7 +++ packages/react-devtools-shared/src/bridge.js | 6 +- .../src/devtools/store.js | 25 +++++++++ .../views/Settings/DebuggingSettings.js | 47 ++++++++++++---- .../views/Settings/SettingsContext.js | 55 ------------------- .../devtools/views/Settings/SettingsModal.js | 17 +++--- .../views/Settings/SettingsModalContext.js | 42 +++++++++++--- packages/react-devtools-shared/src/hook.js | 2 + 11 files changed, 145 insertions(+), 99 deletions(-) diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index d588d4f91e9f0..6949d6019145a 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -162,7 +162,7 @@ export function connectToDevTools(options: ?ConnectOptions) { ); if (devToolsSettingsManager != null && bridge != null) { - bridge.addListener('updateConsolePatchSettings', consolePatchSettings => + bridge.addListener('updateHookSettings', consolePatchSettings => cacheConsolePatchSettings( devToolsSettingsManager, consolePatchSettings, @@ -368,7 +368,7 @@ export function connectWithCustomMessagingProtocol({ ); if (settingsManager != null) { - bridge.addListener('updateConsolePatchSettings', consolePatchSettings => + bridge.addListener('updateHookSettings', consolePatchSettings => cacheConsolePatchSettings(settingsManager, consolePatchSettings), ); } diff --git a/packages/react-devtools-core/src/cachedSettings.js b/packages/react-devtools-core/src/cachedSettings.js index afe12bfdbc5ad..5c603447e8d88 100644 --- a/packages/react-devtools-core/src/cachedSettings.js +++ b/packages/react-devtools-core/src/cachedSettings.js @@ -66,7 +66,7 @@ function parseConsolePatchSettings( export function cacheConsolePatchSettings( devToolsSettingsManager: DevToolsSettingsManager, - value: ConsolePatchSettings, + value: $ReadOnly, ): void { if (devToolsSettingsManager.setConsolePatchSettings == null) { return; diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index 814c6c1c40e67..277b743f3f6a4 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -150,6 +150,7 @@ export default class Agent extends EventEmitter<{ disableTraceUpdates: [], getIfHasUnsupportedRendererVersion: [], updateHookSettings: [DevToolsHookSettings], + getHookSettings: [], }> { _bridge: BackendBridge; _isProfiling: boolean = false; @@ -213,10 +214,10 @@ export default class Agent extends EventEmitter<{ this.syncSelectionFromBuiltinElementsPanel, ); bridge.addListener('shutdown', this.shutdown); - bridge.addListener( - 'updateConsolePatchSettings', - this.updateConsolePatchSettings, - ); + + bridge.addListener('updateHookSettings', this.updateHookSettings); + bridge.addListener('getHookSettings', this.getHookSettings); + bridge.addListener('updateComponentFilters', this.updateComponentFilters); bridge.addListener('getEnvironmentNames', this.getEnvironmentNames); bridge.addListener( @@ -802,18 +803,26 @@ export default class Agent extends EventEmitter<{ } }; - updateConsolePatchSettings: ( - settings: $ReadOnly, - ) => void = settings => { - // Propagate the settings, so Backend can subscribe to it and modify hook - this.emit('updateHookSettings', { - appendComponentStack: settings.appendComponentStack, - breakOnConsoleErrors: settings.breakOnConsoleErrors, - showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode, - }); + updateHookSettings: (settings: $ReadOnly) => void = + settings => { + // Propagate the settings, so Backend can subscribe to it and modify hook + this.emit('updateHookSettings', { + appendComponentStack: settings.appendComponentStack, + breakOnConsoleErrors: settings.breakOnConsoleErrors, + showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors, + hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode, + }); + }; + + getHookSettings: () => void = () => { + this.emit('getHookSettings'); }; + onHookSettings: (settings: $ReadOnly) => void = + settings => { + this._bridge.send('hookSettings', settings); + }; + updateComponentFilters: (componentFilters: Array) => void = componentFilters => { for (const rendererIDString in this._rendererInterfaces) { diff --git a/packages/react-devtools-shared/src/backend/index.js b/packages/react-devtools-shared/src/backend/index.js index 5d84bf6bb70f0..5893424b394c8 100644 --- a/packages/react-devtools-shared/src/backend/index.js +++ b/packages/react-devtools-shared/src/backend/index.js @@ -54,6 +54,7 @@ export function initBackend( hook.sub('fastRefreshScheduled', agent.onFastRefreshScheduled), hook.sub('operations', agent.onHookOperations), hook.sub('traceUpdates', agent.onTraceUpdates), + hook.sub('settingsInitialized', agent.onHookSettings), // TODO Add additional subscriptions required for profiling mode ]; @@ -87,6 +88,12 @@ export function initBackend( hook.settings = settings; }); + agent.addListener('getHookSettings', () => { + if (hook.settings != null) { + agent.onHookSettings(hook.settings); + } + }); + return () => { subs.forEach(fn => fn()); }; diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index 156319b366d71..4751f70cfaefb 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -207,6 +207,8 @@ export type BackendEvents = { {isSupported: boolean, validAttributes: ?$ReadOnlyArray}, ], NativeStyleEditor_styleAndLayout: [StyleAndLayoutPayload], + + hookSettings: [$ReadOnly], }; type FrontendEvents = { @@ -241,7 +243,7 @@ type FrontendEvents = { storeAsGlobal: [StoreAsGlobalParams], updateComponentFilters: [Array], getEnvironmentNames: [], - updateConsolePatchSettings: [DevToolsHookSettings], + updateHookSettings: [$ReadOnly], viewAttributeSource: [ViewAttributeSourceParams], viewElementSource: [ElementAndRendererID], @@ -267,6 +269,8 @@ type FrontendEvents = { resumeElementPolling: [], pauseElementPolling: [], + + getHookSettings: [], }; class Bridge< diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js index d351306a44546..1798e0952b8c2 100644 --- a/packages/react-devtools-shared/src/devtools/store.js +++ b/packages/react-devtools-shared/src/devtools/store.js @@ -49,6 +49,7 @@ import type { BridgeProtocol, } from 'react-devtools-shared/src/bridge'; import UnsupportedBridgeOperationError from 'react-devtools-shared/src/UnsupportedBridgeOperationError'; +import type {DevToolsHookSettings} from '../backend/types'; const debug = (methodName: string, ...args: Array) => { if (__DEBUG__) { @@ -94,6 +95,7 @@ export default class Store extends EventEmitter<{ collapseNodesByDefault: [], componentFilters: [], error: [Error], + hookSettings: [$ReadOnly], mutated: [[Array, Map]], recordChangeDescriptions: [], roots: [], @@ -192,6 +194,7 @@ export default class Store extends EventEmitter<{ _weightAcrossRoots: number = 0; _shouldCheckBridgeProtocolCompatibility: boolean = false; + _hookSettings: $ReadOnly | null = null; constructor(bridge: FrontendBridge, config?: Config) { super(); @@ -270,6 +273,7 @@ export default class Store extends EventEmitter<{ bridge.addListener('backendVersion', this.onBridgeBackendVersion); bridge.addListener('saveToClipboard', this.onSaveToClipboard); + bridge.addListener('hookSettings', this.onHookSettings); bridge.addListener('backendInitialized', this.onBackendInitialized); } @@ -1501,8 +1505,29 @@ export default class Store extends EventEmitter<{ this._bridge.send('getBackendVersion'); this._bridge.send('getIfHasUnsupportedRendererVersion'); + this._bridge.send('getHookSettings'); // Warm up cached hook settings }; + getHookSettings: () => void = () => { + if (this._hookSettings != null) { + this.emit('hookSettings', this._hookSettings); + } else { + this._bridge.send('getHookSettings'); + } + }; + + updateHookSettings: (settings: $ReadOnly) => void = + settings => { + this._hookSettings = settings; + this._bridge.send('updateHookSettings', settings); + }; + + onHookSettings: (settings: $ReadOnly) => void = + settings => { + this._hookSettings = settings; + this.emit('hookSettings', settings); + }; + // The Store should never throw an Error without also emitting an event. // Otherwise Store errors will be invisible to users, // but the downstream errors they cause will be reported as bugs. diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js index b28ca67c0bcb4..8bde14e62e606 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js @@ -8,22 +8,49 @@ */ import * as React from 'react'; -import {useContext} from 'react'; -import {SettingsContext} from './SettingsContext'; +import {use, useState, useEffect} from 'react'; + +import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types'; +import type Store from 'react-devtools-shared/src/devtools/store'; import styles from './SettingsShared.css'; -export default function DebuggingSettings(_: {}): React.Node { - const { +type Props = { + hookSettings: Promise<$ReadOnly>, + store: Store, +}; + +export default function DebuggingSettings({ + hookSettings, + store, +}: Props): React.Node { + const usedHookSettings = use(hookSettings); + + const [appendComponentStack, setAppendComponentStack] = useState( + usedHookSettings.appendComponentStack, + ); + const [breakOnConsoleErrors, setBreakOnConsoleErrors] = useState( + usedHookSettings.breakOnConsoleErrors, + ); + const [hideConsoleLogsInStrictMode, setHideConsoleLogsInStrictMode] = + useState(usedHookSettings.hideConsoleLogsInStrictMode); + const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] = + useState(usedHookSettings.showInlineWarningsAndErrors); + + useEffect(() => { + store.updateHookSettings({ + appendComponentStack, + breakOnConsoleErrors, + showInlineWarningsAndErrors, + hideConsoleLogsInStrictMode, + }); + }, [ + store, appendComponentStack, breakOnConsoleErrors, - hideConsoleLogsInStrictMode, - setAppendComponentStack, - setBreakOnConsoleErrors, - setShowInlineWarningsAndErrors, showInlineWarningsAndErrors, - setHideConsoleLogsInStrictMode, - } = useContext(SettingsContext); + hideConsoleLogsInStrictMode, + ]); return (
diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js index 33487c2f553d6..17514d94648ac 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js @@ -20,11 +20,7 @@ import { import { LOCAL_STORAGE_BROWSER_THEME, LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY, - LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS, - LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY, LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, - LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY, - LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE, } from 'react-devtools-shared/src/constants'; import { COMFORTABLE_LINE_HEIGHT, @@ -118,30 +114,10 @@ function SettingsContextController({ LOCAL_STORAGE_BROWSER_THEME, 'auto', ); - const [appendComponentStack, setAppendComponentStack] = - useLocalStorageWithLog( - LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY, - true, - ); - const [breakOnConsoleErrors, setBreakOnConsoleErrors] = - useLocalStorageWithLog( - LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS, - false, - ); const [parseHookNames, setParseHookNames] = useLocalStorageWithLog( LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY, false, ); - const [hideConsoleLogsInStrictMode, setHideConsoleLogsInStrictMode] = - useLocalStorageWithLog( - LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE, - false, - ); - const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] = - useLocalStorageWithLog( - LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY, - true, - ); const [traceUpdatesEnabled, setTraceUpdatesEnabled] = useLocalStorageWithLog( LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, @@ -196,64 +172,33 @@ function SettingsContextController({ } }, [browserTheme, theme, documentElements]); - useEffect(() => { - bridge.send('updateConsolePatchSettings', { - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - }); - }, [ - bridge, - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - ]); - useEffect(() => { bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled); }, [bridge, traceUpdatesEnabled]); const value = useMemo( () => ({ - appendComponentStack, - breakOnConsoleErrors, displayDensity, lineHeight: displayDensity === 'compact' ? COMPACT_LINE_HEIGHT : COMFORTABLE_LINE_HEIGHT, parseHookNames, - setAppendComponentStack, - setBreakOnConsoleErrors, setDisplayDensity, setParseHookNames, setTheme, setTraceUpdatesEnabled, - setShowInlineWarningsAndErrors, - showInlineWarningsAndErrors, - setHideConsoleLogsInStrictMode, - hideConsoleLogsInStrictMode, theme, browserTheme, traceUpdatesEnabled, }), [ - appendComponentStack, - breakOnConsoleErrors, displayDensity, parseHookNames, - setAppendComponentStack, - setBreakOnConsoleErrors, setDisplayDensity, setParseHookNames, setTheme, setTraceUpdatesEnabled, - setShowInlineWarningsAndErrors, - showInlineWarningsAndErrors, - setHideConsoleLogsInStrictMode, - hideConsoleLogsInStrictMode, theme, browserTheme, traceUpdatesEnabled, diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js index 24884098a0bfc..f6652ada3a860 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js @@ -26,9 +26,11 @@ import ProfilerSettings from './ProfilerSettings'; import styles from './SettingsModal.css'; -type TabID = 'general' | 'components' | 'profiler'; +import type Store from 'react-devtools-shared/src/devtools/store'; -export default function SettingsModal(_: {}): React.Node { +type TabID = 'general' | 'debugging' | 'components' | 'profiler'; + +export default function SettingsModal(): React.Node { const {isModalShowing, setIsModalShowing} = useContext(SettingsModalContext); const store = useContext(StoreContext); const {profilerStore} = store; @@ -54,11 +56,13 @@ export default function SettingsModal(_: {}): React.Node { return null; } - return ; + return ; } -function SettingsModalImpl(_: {}) { - const {setIsModalShowing, environmentNames} = +type ImplProps = {store: Store}; + +function SettingsModalImpl({store}: ImplProps) { + const {setIsModalShowing, environmentNames, hookSettings} = useContext(SettingsModalContext); const dismissModal = useCallback( () => setIsModalShowing(false), @@ -84,9 +88,8 @@ function SettingsModalImpl(_: {}) { case 'components': view = ; break; - // $FlowFixMe[incompatible-type] is this missing in TabID? case 'debugging': - view = ; + view = ; break; case 'general': view = ; diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js index 55336a9d650b0..98e491f44b6eb 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js @@ -18,8 +18,11 @@ import { startTransition, } from 'react'; -import {BridgeContext} from '../context'; +import {BridgeContext, StoreContext} from '../context'; + import type {FrontendBridge} from '../../../bridge'; +import type {DevToolsHookSettings} from '../../../backend/types'; +import type Store from '../../store'; export type DisplayDensity = 'comfortable' | 'compact'; export type Theme = 'auto' | 'light' | 'dark'; @@ -28,6 +31,7 @@ type Context = { isModalShowing: boolean, setIsModalShowing: (value: boolean) => void, environmentNames: null | Promise>, + hookSettings: null | Promise<$ReadOnly>, }; const SettingsModalContext: ReactContext = createContext( @@ -46,27 +50,47 @@ function fetchEnvironmentNames(bridge: FrontendBridge): Promise> { }); } +function fetchHookSettings( + store: Store, +): Promise<$ReadOnly> { + return new Promise(resolve => { + function onHookSettings(settings: $ReadOnly) { + store.removeListener('hookSettings', onHookSettings); + resolve(settings); + } + + store.addListener('hookSettings', onHookSettings); + store.getHookSettings(); + }); +} + function SettingsModalContextController({ children, }: { children: React$Node, }): React.Node { const bridge = useContext(BridgeContext); + const store = useContext(StoreContext); - const setIsModalShowing: boolean => void = useCallback((value: boolean) => { - startTransition(() => { - setContext({ - isModalShowing: value, - setIsModalShowing, - environmentNames: value ? fetchEnvironmentNames(bridge) : null, + const setIsModalShowing: boolean => void = useCallback( + (value: boolean) => { + startTransition(() => { + setContext({ + isModalShowing: value, + setIsModalShowing, + environmentNames: value ? fetchEnvironmentNames(bridge) : null, + hookSettings: value ? fetchHookSettings(store) : null, + }); }); - }); - }); + }, + [bridge, store], + ); const [currentContext, setContext] = useState({ isModalShowing: false, setIsModalShowing, environmentNames: null, + hookSettings: null, }); return ( diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 2f0698b8e1353..1916a8c93822c 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -655,6 +655,8 @@ export function installHook( Promise.resolve(maybeSettingsOrSettingsPromise) .then(settings => { hook.settings = settings; + hook.emit('settingsInitialized', settings); + patchConsoleForErrorsAndWarnings(); }) .catch(() => { From f37c7bc6539b4da38f7080b5486eb00bdb2c3237 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 18:26:39 +0100 Subject: [PATCH 169/426] feat[react-devtools/extension]: use chrome.storage to persist settings across sessions (#30636) Stacked on https://github.com/facebook/react/pull/30610 and whats under it. See [last commit](https://github.com/facebook/react/pull/30636/commits/248ddba18608e1bb5ef14c823085a7ff9d7a54a3). Now, we are using [`chrome.storage`](https://developer.chrome.com/docs/extensions/reference/api/storage) to persist settings for the browser extension across different sessions. Once settings are updated from the UI, the `Store` will emit `settingsUpdated` event, and we are going to persist them via `chrome.storage.local.set` in `main/index.js`. When hook is being injected, we are going to pass a `Promise`, which is going to be resolved after the settings are read from the storage via `chrome.storage.local.get` in `hookSettingsInjector.js`. --- .../chrome/manifest.json | 1 + .../edge/manifest.json | 1 + .../firefox/manifest.json | 1 + .../dynamicallyInjectContentScripts.js | 7 ++++ .../contentScripts/hookSettingsInjector.js | 42 +++++++++++++++++++ .../src/contentScripts/installHook.js | 39 +++++++++++++++-- .../src/main/index.js | 10 ++--- .../src/main/syncSavedPreferences.js | 34 --------------- .../webpack.config.js | 1 + .../src/backend/agent.js | 9 +--- .../src/backend/types.js | 2 +- .../src/devtools/store.js | 3 ++ 12 files changed, 99 insertions(+), 51 deletions(-) create mode 100644 packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js delete mode 100644 packages/react-devtools-extensions/src/main/syncSavedPreferences.js diff --git a/packages/react-devtools-extensions/chrome/manifest.json b/packages/react-devtools-extensions/chrome/manifest.json index e61ebd1e57ed0..1ab43194f2620 100644 --- a/packages/react-devtools-extensions/chrome/manifest.json +++ b/packages/react-devtools-extensions/chrome/manifest.json @@ -42,6 +42,7 @@ }, "permissions": [ "scripting", + "storage", "tabs" ], "host_permissions": [ diff --git a/packages/react-devtools-extensions/edge/manifest.json b/packages/react-devtools-extensions/edge/manifest.json index 48a56c7400ce4..bd03dea08efb3 100644 --- a/packages/react-devtools-extensions/edge/manifest.json +++ b/packages/react-devtools-extensions/edge/manifest.json @@ -42,6 +42,7 @@ }, "permissions": [ "scripting", + "storage", "tabs" ], "host_permissions": [ diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json index 930c1ab11083e..8a5a272fb4500 100644 --- a/packages/react-devtools-extensions/firefox/manifest.json +++ b/packages/react-devtools-extensions/firefox/manifest.json @@ -49,6 +49,7 @@ }, "permissions": [ "scripting", + "storage", "tabs" ], "host_permissions": [ diff --git a/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js b/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js index 9398d71a54e7c..f1a3598a519ca 100644 --- a/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js +++ b/packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js @@ -25,6 +25,13 @@ const contentScriptsToInject = [ runAt: 'document_start', world: chrome.scripting.ExecutionWorld.MAIN, }, + { + id: '@react-devtools/hook-settings-injector', + js: ['build/hookSettingsInjector.js'], + matches: [''], + persistAcrossSessions: true, + runAt: 'document_start', + }, ]; async function dynamicallyInjectContentScripts() { diff --git a/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js b/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js new file mode 100644 index 0000000000000..e26108edac7e6 --- /dev/null +++ b/packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js @@ -0,0 +1,42 @@ +/* global chrome */ + +// We can't use chrome.storage domain from scripts which are injected in ExecutionWorld.MAIN +// This is the only purpose of this script - to send persisted settings to installHook.js content script + +async function messageListener(event: MessageEvent) { + if (event.source !== window) { + return; + } + + if (event.data.source === 'react-devtools-hook-installer') { + if (event.data.payload.handshake) { + const settings = await chrome.storage.local.get(); + // If storage was empty (first installation), define default settings + if (typeof settings.appendComponentStack !== 'boolean') { + settings.appendComponentStack = true; + } + if (typeof settings.breakOnConsoleErrors !== 'boolean') { + settings.breakOnConsoleErrors = false; + } + if (typeof settings.showInlineWarningsAndErrors !== 'boolean') { + settings.showInlineWarningsAndErrors = true; + } + if (typeof settings.hideConsoleLogsInStrictMode !== 'boolean') { + settings.hideConsoleLogsInStrictMode = false; + } + + window.postMessage({ + source: 'react-devtools-hook-settings-injector', + payload: {settings}, + }); + + window.removeEventListener('message', messageListener); + } + } +} + +window.addEventListener('message', messageListener); +window.postMessage({ + source: 'react-devtools-hook-settings-injector', + payload: {handshake: true}, +}); diff --git a/packages/react-devtools-extensions/src/contentScripts/installHook.js b/packages/react-devtools-extensions/src/contentScripts/installHook.js index ff7e041627f0e..b7b96ed24714b 100644 --- a/packages/react-devtools-extensions/src/contentScripts/installHook.js +++ b/packages/react-devtools-extensions/src/contentScripts/installHook.js @@ -1,10 +1,43 @@ import {installHook} from 'react-devtools-shared/src/hook'; -// avoid double execution +let resolveHookSettingsInjection; + +function messageListener(event: MessageEvent) { + if (event.source !== window) { + return; + } + + if (event.data.source === 'react-devtools-hook-settings-injector') { + // In case handshake message was sent prior to hookSettingsInjector execution + // We can't guarantee order + if (event.data.payload.handshake) { + window.postMessage({ + source: 'react-devtools-hook-installer', + payload: {handshake: true}, + }); + } else if (event.data.payload.settings) { + window.removeEventListener('message', messageListener); + resolveHookSettingsInjection(event.data.payload.settings); + } + } +} + +// Avoid double execution if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { - installHook(window); + const hookSettingsPromise = new Promise(resolve => { + resolveHookSettingsInjection = resolve; + }); + + window.addEventListener('message', messageListener); + window.postMessage({ + source: 'react-devtools-hook-installer', + payload: {handshake: true}, + }); + + // Can't delay hook installation, inject settings lazily + installHook(window, hookSettingsPromise); - // detect react + // Detect React window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on( 'renderer', function ({reactBuildType}) { diff --git a/packages/react-devtools-extensions/src/main/index.js b/packages/react-devtools-extensions/src/main/index.js index 36931e42194a4..a2758567138c8 100644 --- a/packages/react-devtools-extensions/src/main/index.js +++ b/packages/react-devtools-extensions/src/main/index.js @@ -27,7 +27,6 @@ import {startReactPolling} from './reactPolling'; import cloneStyleTags from './cloneStyleTags'; import fetchFileWithCaching from './fetchFileWithCaching'; import injectBackendManager from './injectBackendManager'; -import syncSavedPreferences from './syncSavedPreferences'; import registerEventsLogger from './registerEventsLogger'; import getProfilingFlags from './getProfilingFlags'; import debounce from './debounce'; @@ -103,6 +102,10 @@ function createBridgeAndStore() { supportsClickToInspect: true, }); + store.addListener('settingsUpdated', settings => { + chrome.storage.local.set(settings); + }); + if (!isProfiling) { // We previously stored this in performCleanup function store.profilerStore.profilingData = profilingData; @@ -393,10 +396,6 @@ let root = null; let port = null; -// Re-initialize saved filters on navigation, -// since global values stored on window get reset in this case. -chrome.devtools.network.onNavigated.addListener(syncSavedPreferences); - // In case when multiple navigation events emitted in a short period of time // This debounced callback primarily used to avoid mounting React DevTools multiple times, which results // into subscribing to the same events from Bridge and window multiple times @@ -426,5 +425,4 @@ if (__IS_FIREFOX__) { connectExtensionPort(); -syncSavedPreferences(); mountReactDevToolsWhenReactHasLoaded(); diff --git a/packages/react-devtools-extensions/src/main/syncSavedPreferences.js b/packages/react-devtools-extensions/src/main/syncSavedPreferences.js deleted file mode 100644 index f22d41eb7c904..0000000000000 --- a/packages/react-devtools-extensions/src/main/syncSavedPreferences.js +++ /dev/null @@ -1,34 +0,0 @@ -/* global chrome */ - -import { - getAppendComponentStack, - getBreakOnConsoleErrors, - getSavedComponentFilters, - getShowInlineWarningsAndErrors, - getHideConsoleLogsInStrictMode, -} from 'react-devtools-shared/src/utils'; - -// The renderer interface can't read saved component filters directly, -// because they are stored in localStorage within the context of the extension. -// Instead it relies on the extension to pass filters through. -function syncSavedPreferences() { - chrome.devtools.inspectedWindow.eval( - `window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = ${JSON.stringify( - getAppendComponentStack(), - )}; - window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = ${JSON.stringify( - getBreakOnConsoleErrors(), - )}; - window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = ${JSON.stringify( - getSavedComponentFilters(), - )}; - window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = ${JSON.stringify( - getShowInlineWarningsAndErrors(), - )}; - window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = ${JSON.stringify( - getHideConsoleLogsInStrictMode(), - )};`, - ); -} - -export default syncSavedPreferences; diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js index ddbb4356f658c..e6d40a1f20ad2 100644 --- a/packages/react-devtools-extensions/webpack.config.js +++ b/packages/react-devtools-extensions/webpack.config.js @@ -56,6 +56,7 @@ module.exports = { proxy: './src/contentScripts/proxy.js', prepareInjection: './src/contentScripts/prepareInjection.js', installHook: './src/contentScripts/installHook.js', + hookSettingsInjector: './src/contentScripts/hookSettingsInjector.js', }, output: { path: __dirname + '/build', diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index 277b743f3f6a4..e55e8a6d41e2b 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -149,7 +149,7 @@ export default class Agent extends EventEmitter<{ drawTraceUpdates: [Array], disableTraceUpdates: [], getIfHasUnsupportedRendererVersion: [], - updateHookSettings: [DevToolsHookSettings], + updateHookSettings: [$ReadOnly], getHookSettings: [], }> { _bridge: BackendBridge; @@ -806,12 +806,7 @@ export default class Agent extends EventEmitter<{ updateHookSettings: (settings: $ReadOnly) => void = settings => { // Propagate the settings, so Backend can subscribe to it and modify hook - this.emit('updateHookSettings', { - appendComponentStack: settings.appendComponentStack, - breakOnConsoleErrors: settings.breakOnConsoleErrors, - showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode, - }); + this.emit('updateHookSettings', settings); }; getHookSettings: () => void = () => { diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index bdc93a19baa8b..4065b536afeeb 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -524,7 +524,7 @@ export type DevToolsHook = { // Testing dangerous_setTargetConsoleForTesting?: (fakeConsole: Object) => void, - settings?: DevToolsHookSettings, + settings?: $ReadOnly, ... }; diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js index 1798e0952b8c2..b54907338b372 100644 --- a/packages/react-devtools-shared/src/devtools/store.js +++ b/packages/react-devtools-shared/src/devtools/store.js @@ -96,6 +96,7 @@ export default class Store extends EventEmitter<{ componentFilters: [], error: [Error], hookSettings: [$ReadOnly], + settingsUpdated: [$ReadOnly], mutated: [[Array, Map]], recordChangeDescriptions: [], roots: [], @@ -1519,7 +1520,9 @@ export default class Store extends EventEmitter<{ updateHookSettings: (settings: $ReadOnly) => void = settings => { this._hookSettings = settings; + this._bridge.send('updateHookSettings', settings); + this.emit('settingsUpdated', settings); }; onHookSettings: (settings: $ReadOnly) => void = From f2c57a31e9953b3889c56f68e129e67afca15d0e Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 18 Sep 2024 18:30:32 +0100 Subject: [PATCH 170/426] chore: remove settings manager from react-devtools-core (#30986) Stacked on https://github.com/facebook/react/pull/30636. See [this commit](https://github.com/facebook/react/pull/30986/commits/20cec76c44f77e74b3a85225fecab5a431cd986f). This has been only used for React Native and will be replaced by another approach (initialization via `installHook` call) in the next PR. --- packages/react-devtools-core/src/backend.js | 44 ----------- .../react-devtools-core/src/cachedSettings.js | 75 ------------------- .../src/backend/console.js | 26 ------- .../src/backend/types.js | 3 - 4 files changed, 148 deletions(-) delete mode 100644 packages/react-devtools-core/src/cachedSettings.js delete mode 100644 packages/react-devtools-shared/src/backend/console.js diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index 6949d6019145a..84f537e875d00 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -14,11 +14,6 @@ import {initBackend} from 'react-devtools-shared/src/backend'; import {__DEBUG__} from 'react-devtools-shared/src/constants'; import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils'; -import { - initializeUsingCachedSettings, - cacheConsolePatchSettings, - type DevToolsSettingsManager, -} from './cachedSettings'; import type {BackendBridge} from 'react-devtools-shared/src/bridge'; import type { @@ -37,7 +32,6 @@ type ConnectOptions = { retryConnectionDelay?: number, isAppActive?: () => boolean, websocket?: ?WebSocket, - devToolsSettingsManager: ?DevToolsSettingsManager, }; installHook(window); @@ -72,7 +66,6 @@ export function connectToDevTools(options: ?ConnectOptions) { resolveRNStyle = (null: $FlowFixMe), retryConnectionDelay = 2000, isAppActive = () => true, - devToolsSettingsManager, } = options || {}; const protocol = useHttps ? 'wss' : 'ws'; @@ -88,16 +81,6 @@ export function connectToDevTools(options: ?ConnectOptions) { } } - if (devToolsSettingsManager != null) { - try { - initializeUsingCachedSettings(devToolsSettingsManager); - } catch (e) { - // If we call a method on devToolsSettingsManager that throws, or if - // is invalid data read out, don't throw and don't interrupt initialization - console.error(e); - } - } - if (!isAppActive()) { // If the app is in background, maybe retry later. // Don't actually attempt to connect until we're in foreground. @@ -161,15 +144,6 @@ export function connectToDevTools(options: ?ConnectOptions) { }, ); - if (devToolsSettingsManager != null && bridge != null) { - bridge.addListener('updateHookSettings', consolePatchSettings => - cacheConsolePatchSettings( - devToolsSettingsManager, - consolePatchSettings, - ), - ); - } - // The renderer interface doesn't read saved component filters directly, // because they are generally stored in localStorage within the context of the extension. // Because of this it relies on the extension to pass filters. @@ -314,7 +288,6 @@ type ConnectWithCustomMessagingOptions = { onSubscribe: (cb: Function) => void, onUnsubscribe: (cb: Function) => void, onMessage: (event: string, payload: any) => void, - settingsManager: ?DevToolsSettingsManager, nativeStyleEditorValidAttributes?: $ReadOnlyArray, resolveRNStyle?: ResolveNativeStyle, }; @@ -323,7 +296,6 @@ export function connectWithCustomMessagingProtocol({ onSubscribe, onUnsubscribe, onMessage, - settingsManager, nativeStyleEditorValidAttributes, resolveRNStyle, }: ConnectWithCustomMessagingOptions): Function { @@ -332,16 +304,6 @@ export function connectWithCustomMessagingProtocol({ return; } - if (settingsManager != null) { - try { - initializeUsingCachedSettings(settingsManager); - } catch (e) { - // If we call a method on devToolsSettingsManager that throws, or if - // is invalid data read out, don't throw and don't interrupt initialization - console.error(e); - } - } - const wall: Wall = { listen(fn: Function) { onSubscribe(fn); @@ -367,12 +329,6 @@ export function connectWithCustomMessagingProtocol({ }, ); - if (settingsManager != null) { - bridge.addListener('updateHookSettings', consolePatchSettings => - cacheConsolePatchSettings(settingsManager, consolePatchSettings), - ); - } - if (window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ == null) { bridge.send('overrideComponentFilters', savedComponentFilters); } diff --git a/packages/react-devtools-core/src/cachedSettings.js b/packages/react-devtools-core/src/cachedSettings.js deleted file mode 100644 index 5c603447e8d88..0000000000000 --- a/packages/react-devtools-core/src/cachedSettings.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and its 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 type {ConsolePatchSettings} from 'react-devtools-shared/src/backend/types'; -import {writeConsolePatchSettingsToWindow} from 'react-devtools-shared/src/backend/console'; -import {castBool} from 'react-devtools-shared/src/utils'; - -// Note: all keys should be optional in this type, because users can use newer -// versions of React DevTools with older versions of React Native, and the object -// provided by React Native may not include all of this type's fields. -export type DevToolsSettingsManager = { - getConsolePatchSettings: ?() => string, - setConsolePatchSettings: ?(key: string) => void, -}; - -export function initializeUsingCachedSettings( - devToolsSettingsManager: DevToolsSettingsManager, -) { - initializeConsolePatchSettings(devToolsSettingsManager); -} - -function initializeConsolePatchSettings( - devToolsSettingsManager: DevToolsSettingsManager, -) { - if (devToolsSettingsManager.getConsolePatchSettings == null) { - return; - } - const consolePatchSettingsString = - devToolsSettingsManager.getConsolePatchSettings(); - if (consolePatchSettingsString == null) { - return; - } - const parsedConsolePatchSettings = parseConsolePatchSettings( - consolePatchSettingsString, - ); - if (parsedConsolePatchSettings == null) { - return; - } - writeConsolePatchSettingsToWindow(parsedConsolePatchSettings); -} - -function parseConsolePatchSettings( - consolePatchSettingsString: string, -): ?ConsolePatchSettings { - const parsedValue = JSON.parse(consolePatchSettingsString ?? '{}'); - const { - appendComponentStack, - breakOnConsoleErrors, - showInlineWarningsAndErrors, - hideConsoleLogsInStrictMode, - } = parsedValue; - - return { - appendComponentStack: castBool(appendComponentStack) ?? true, - breakOnConsoleErrors: castBool(breakOnConsoleErrors) ?? false, - showInlineWarningsAndErrors: castBool(showInlineWarningsAndErrors) ?? true, - hideConsoleLogsInStrictMode: castBool(hideConsoleLogsInStrictMode) ?? false, - }; -} - -export function cacheConsolePatchSettings( - devToolsSettingsManager: DevToolsSettingsManager, - value: $ReadOnly, -): void { - if (devToolsSettingsManager.setConsolePatchSettings == null) { - return; - } - devToolsSettingsManager.setConsolePatchSettings(JSON.stringify(value)); -} diff --git a/packages/react-devtools-shared/src/backend/console.js b/packages/react-devtools-shared/src/backend/console.js deleted file mode 100644 index 9e61285b50fe4..0000000000000 --- a/packages/react-devtools-shared/src/backend/console.js +++ /dev/null @@ -1,26 +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. - * - * @flow - */ - -import type {ConsolePatchSettings} from './types'; - -// After receiving cached console patch settings from React Native, we set them on window. -// When the console is initially patched (in renderer.js and hook.js), these values are read. -// The browser extension (etc.) sets these values on window, but through another method. -export function writeConsolePatchSettingsToWindow( - settings: ConsolePatchSettings, -): void { - window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = - settings.appendComponentStack; - window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = - settings.breakOnConsoleErrors; - window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = - settings.showInlineWarningsAndErrors; - window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = - settings.hideConsoleLogsInStrictMode; -} diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 4065b536afeeb..c3110dc517fdc 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -534,6 +534,3 @@ export type DevToolsHookSettings = { showInlineWarningsAndErrors: boolean, hideConsoleLogsInStrictMode: boolean, }; - -// Will be removed together with console patching from backend/console.js to hook.js -export type ConsolePatchSettings = DevToolsHookSettings; From 09d82835993b16cd5dc8350c03627f9573354a25 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:39:04 -0400 Subject: [PATCH 171/426] [ez] Rewrite optional chaining and nullish coalescing syntax (#30982) Rewrite `containerInfo?.ownerDocument?.defaultView ?? window` to instead use a ternary. This changes the compilation output (see [bundle changes from #30951](https://github.com/facebook/react/commit/d65fb06955e9f32e6a40d1c7177d77893dff95b9)). ```js // compilation of containerInfo?.ownerDocument?.defaultView ?? window var $jscomp$optchain$tmpm1756096108$1, $jscomp$nullish$tmp0; containerInfo = null != ($jscomp$nullish$tmp0 = null == containerInfo ? void 0 : null == ($jscomp$optchain$tmpm1756096108$1 = containerInfo.ownerDocument) ? void 0 : $jscomp$optchain$tmpm1756096108$1.defaultView) ? $jscomp$nullish$tmp0 : window; // compilation of ternary expression containerInfo = null != containerInfo && null != containerInfo.ownerDocument && null != containerInfo.ownerDocument.defaultView ? containerInfo.ownerDocument.defaultView : window; ``` This also reduces the number of no-op bundle syncs for Meta. Note that Closure compiler's `jscomp$optchain$tmp` identifiers change when we rebuild (likely due to version number changes). See [workflow](https://github.com/facebook/react/actions/runs/10891164281/job/30221518374) for a PR that was synced despite making no changes to the runtime. --- .../react-dom-bindings/src/client/ReactInputSelection.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-dom-bindings/src/client/ReactInputSelection.js b/packages/react-dom-bindings/src/client/ReactInputSelection.js index 0f3dfe11cd9f9..36cdc554f0f44 100644 --- a/packages/react-dom-bindings/src/client/ReactInputSelection.js +++ b/packages/react-dom-bindings/src/client/ReactInputSelection.js @@ -57,7 +57,12 @@ function isSameOriginFrame(iframe) { } function getActiveElementDeep(containerInfo) { - let win = containerInfo?.ownerDocument?.defaultView ?? window; + let win = + containerInfo != null && + containerInfo.ownerDocument != null && + containerInfo.ownerDocument.defaultView != null + ? containerInfo.ownerDocument.defaultView + : window; let element = getActiveElement(win.document); while (element instanceof win.HTMLIFrameElement) { if (isSameOriginFrame(element)) { From e72127a4ec6f91288e9008711215068823100599 Mon Sep 17 00:00:00 2001 From: Timothy Yung Date: Wed, 18 Sep 2024 14:44:55 -0700 Subject: [PATCH 172/426] Build `react-dom` in `builds/facebook-fbsource` (#30711) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Builds `react-dom` for React Native so that it also populates the `builds/facebook-fbsource` branch. **NOTE:** For Meta employees, D61354219 is the internal integration. ## How did you test this change? ``` $ yarn build … $ ls build/facebook-react-native/react-dom/cjs ReactDOM-dev.js ReactDOM-prod.js ReactDOM-profiling.js ``` --- .../workflows/runtime_commit_artifacts.yml | 1 + scripts/rollup/bundles.js | 48 ++++++++++++++++++- scripts/rollup/packaging.js | 1 + 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index f47eb3ff360e9..ed0c59caf883e 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -125,6 +125,7 @@ jobs: mv build/react-native/shims/ $BASE_FOLDER/react-native-github/Libraries/Renderer/ mv build/facebook-react-native/scheduler/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/scheduler/ mv build/facebook-react-native/react/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react/ + mv build/facebook-react-native/react/dom/ $BASE_FOLDER/RKJSModules/vendor/react/react-dom/ mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/ mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/ diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 081b91b9d0b80..26a88fb00811d 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -183,6 +183,7 @@ const bundles = [ wrapWithModuleBoundaries: true, externals: ['react'], }, + /******* React DOM Client *******/ { bundleTypes: [NODE_DEV, NODE_PROD], @@ -204,7 +205,8 @@ const bundles = [ wrapWithModuleBoundaries: true, externals: ['react', 'react-dom'], }, - /******* React DOM FB *******/ + + /******* React DOM (www) *******/ { bundleTypes: [FB_WWW_DEV, FB_WWW_PROD, FB_WWW_PROFILING], moduleType: RENDERER, @@ -215,6 +217,50 @@ const bundles = [ externals: ['react'], }, + /******* React DOM (fbsource) *******/ + { + bundleTypes: [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING], + moduleType: RENDERER, + entry: 'react-dom', + global: 'ReactDOM', + minifyWithProdErrorCodes: true, + wrapWithModuleBoundaries: false, + externals: ['react', 'ReactNativeInternalFeatureFlags'], + }, + + /******* React DOM Client (fbsource) *******/ + { + bundleTypes: [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING], + moduleType: RENDERER, + entry: 'react-dom/client', + global: 'ReactDOMClient', + minifyWithProdErrorCodes: true, + wrapWithModuleBoundaries: false, + externals: ['react', 'react-dom', 'ReactNativeInternalFeatureFlags'], + }, + + /******* React DOM Profiling (fbsource) *******/ + { + bundleTypes: [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING], + moduleType: RENDERER, + entry: 'react-dom/profiling', + global: 'ReactDOMProfiling', + minifyWithProdErrorCodes: true, + wrapWithModuleBoundaries: true, + externals: ['react', 'react-dom', 'ReactNativeInternalFeatureFlags'], + }, + + /******* React DOM Test Utils (fbsource) *******/ + { + moduleType: RENDERER_UTILS, + bundleTypes: [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING], + entry: 'react-dom/test-utils', + global: 'ReactDOMTestUtils', + minifyWithProdErrorCodes: false, + wrapWithModuleBoundaries: false, + externals: ['react', 'react-dom', 'ReactNativeInternalFeatureFlags'], + }, + /******* React DOM React Server *******/ { bundleTypes: [NODE_DEV, NODE_PROD], diff --git a/scripts/rollup/packaging.js b/scripts/rollup/packaging.js index 7c433fc2dd330..bc83cb8789eb8 100644 --- a/scripts/rollup/packaging.js +++ b/scripts/rollup/packaging.js @@ -76,6 +76,7 @@ function getBundleOutputPath(bundle, bundleType, filename, packageName) { switch (packageName) { case 'scheduler': case 'react': + case 'react-dom': case 'react-is': case 'react-test-renderer': return `build/facebook-react-native/${packageName}/cjs/${filename}`; From a86afe8e560f452a9df5ceb4893d9423e5840800 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 19 Sep 2024 13:55:08 +0100 Subject: [PATCH 173/426] feat: expose installHook with settings argument from react-devtools-core/backend (#30987) Stacked on https://github.com/facebook/react/pull/30986. Previously, we would call `installHook` at a top level of the JavaScript module. Because of this, having `require` statement for `react-devtools-core` package was enough to initialize the React DevTools global hook on the `window`. Now, the Hook can actually receive an argument - initial user settings for console patching. We expose this as a function `initialize`, which can be used by third parties (including React Native) to provide the persisted settings. The README was also updated to reflect the changes. --- packages/react-devtools-core/README.md | 47 +++++++++++++-------- packages/react-devtools-core/src/backend.js | 38 ++++++++++++++--- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/packages/react-devtools-core/README.md b/packages/react-devtools-core/README.md index b0f0e98191b35..f3487fefba75e 100644 --- a/packages/react-devtools-core/README.md +++ b/packages/react-devtools-core/README.md @@ -14,35 +14,46 @@ If you are building a non-browser-based React renderer, you can use the backend ```js if (process.env.NODE_ENV !== 'production') { - const { connectToDevTools } = require("react-devtools-core"); + const { initialize, connectToDevTools } = require("react-devtools-core"); + initialize(settings); // Must be called before packages like react or react-native are imported - connectToDevTools({ - ...config - }); + connectToDevTools({...config}); } ``` > **NOTE** that this API (`connectToDevTools`) must be (1) run in the same context as React and (2) must be called before React packages are imported (e.g. `react`, `react-dom`, `react-native`). +### `initialize` arguments +| Argument | Description | +|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `settings` | Optional. If not specified, or received as null, then default settings are used. Can be plain object or a Promise that resolves with the [plain settings object](#Settings). If Promise rejects, the console will not be patched and some console features from React DevTools will not work. | + +#### `Settings` +| Spec | Default value | +|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|
{
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
showInlineWarningsAndErrors: boolean,
hideConsoleLogsInStrictMode: boolean
}
|
{
appendComponentStack: true,
breakOnConsoleErrors: false,
showInlineWarningsAndErrors: true,
hideConsoleLogsInStrictMode: false
}
| + ### `connectToDevTools` options -| Prop | Default | Description | -|---|---|---| -| `host` | `"localhost"` | Socket connection to frontend should use this host. | -| `isAppActive` | | (Optional) function that returns true/false, telling DevTools when it's ready to connect to React. | -| `port` | `8097` | Socket connection to frontend should use this port. | -| `resolveRNStyle` | | (Optional) function that accepts a key (number) and returns a style (object); used by React Native. | -| `retryConnectionDelay` | `200` | Delay (ms) to wait between retrying a failed Websocket connection | -| `useHttps` | `false` | Socket connection to frontend should use secure protocol (wss). | -| `websocket` | | Custom `WebSocket` connection to frontend; overrides `host` and `port` settings. | +| Prop | Default | Description | +|------------------------|---------------|---------------------------------------------------------------------------------------------------------------------------| +| `host` | `"localhost"` | Socket connection to frontend should use this host. | +| `isAppActive` | | (Optional) function that returns true/false, telling DevTools when it's ready to connect to React. | +| `port` | `8097` | Socket connection to frontend should use this port. | +| `resolveRNStyle` | | (Optional) function that accepts a key (number) and returns a style (object); used by React Native. | +| `retryConnectionDelay` | `200` | Delay (ms) to wait between retrying a failed Websocket connection | +| `useHttps` | `false` | Socket connection to frontend should use secure protocol (wss). | +| `websocket` | | Custom `WebSocket` connection to frontend; overrides `host` and `port` settings. | +| `onSettingsUpdated` | | A callback that will be called when the user updates the settings in the UI. You can use it for persisting user settings. | | ### `connectWithCustomMessagingProtocol` options -| Prop | Description | -|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `onSubscribe` | Function, which receives listener (function, with a single argument) as an argument. Called when backend subscribes to messages from the other end (frontend). | -| `onUnsubscribe` | Function, which receives listener (function) as an argument. Called when backend unsubscribes to messages from the other end (frontend). | -| `onMessage` | Function, which receives 2 arguments: event (string) and payload (any). Called when backend emits a message, which should be sent to the frontend. | +| Prop | Description | +|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `onSubscribe` | Function, which receives listener (function, with a single argument) as an argument. Called when backend subscribes to messages from the other end (frontend). | +| `onUnsubscribe` | Function, which receives listener (function) as an argument. Called when backend unsubscribes to messages from the other end (frontend). | +| `onMessage` | Function, which receives 2 arguments: event (string) and payload (any). Called when backend emits a message, which should be sent to the frontend. | +| `onSettingsUpdated` | A callback that will be called when the user updates the settings in the UI. You can use it for persisting user settings. | Unlike `connectToDevTools`, `connectWithCustomMessagingProtocol` returns a callback, which can be used for unsubscribing the backend from the global DevTools hook. diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index 84f537e875d00..1f2055832a3dd 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -20,7 +20,10 @@ import type { ComponentFilter, Wall, } from 'react-devtools-shared/src/frontend/types'; -import type {DevToolsHook} from 'react-devtools-shared/src/backend/types'; +import type { + DevToolsHook, + DevToolsHookSettings, +} from 'react-devtools-shared/src/backend/types'; import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; type ConnectOptions = { @@ -32,12 +35,9 @@ type ConnectOptions = { retryConnectionDelay?: number, isAppActive?: () => boolean, websocket?: ?WebSocket, + onSettingsUpdated?: (settings: $ReadOnly) => void, }; -installHook(window); - -const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; - let savedComponentFilters: Array = getDefaultComponentFilters(); @@ -52,11 +52,21 @@ function debug(methodName: string, ...args: Array) { } } +export function initialize( + maybeSettingsOrSettingsPromise?: + | DevToolsHookSettings + | Promise, +) { + installHook(window, maybeSettingsOrSettingsPromise); +} + export function connectToDevTools(options: ?ConnectOptions) { + const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook == null) { // DevTools didn't get injected into this page (maybe b'c of the contentType). return; } + const { host = 'localhost', nativeStyleEditorValidAttributes, @@ -66,6 +76,7 @@ export function connectToDevTools(options: ?ConnectOptions) { resolveRNStyle = (null: $FlowFixMe), retryConnectionDelay = 2000, isAppActive = () => true, + onSettingsUpdated, } = options || {}; const protocol = useHttps ? 'wss' : 'ws'; @@ -160,7 +171,14 @@ export function connectToDevTools(options: ?ConnectOptions) { // TODO (npm-packages) Warn if "isBackendStorageAPISupported" // $FlowFixMe[incompatible-call] found when upgrading Flow const agent = new Agent(bridge); + if (onSettingsUpdated != null) { + agent.addListener('updateHookSettings', onSettingsUpdated); + } agent.addListener('shutdown', () => { + if (onSettingsUpdated != null) { + agent.removeListener('updateHookSettings', onSettingsUpdated); + } + // If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down, // and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here. hook.emit('shutdown'); @@ -290,6 +308,7 @@ type ConnectWithCustomMessagingOptions = { onMessage: (event: string, payload: any) => void, nativeStyleEditorValidAttributes?: $ReadOnlyArray, resolveRNStyle?: ResolveNativeStyle, + onSettingsUpdated?: (settings: $ReadOnly) => void, }; export function connectWithCustomMessagingProtocol({ @@ -298,7 +317,9 @@ export function connectWithCustomMessagingProtocol({ onMessage, nativeStyleEditorValidAttributes, resolveRNStyle, + onSettingsUpdated, }: ConnectWithCustomMessagingOptions): Function { + const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook == null) { // DevTools didn't get injected into this page (maybe b'c of the contentType). return; @@ -334,7 +355,14 @@ export function connectWithCustomMessagingProtocol({ } const agent = new Agent(bridge); + if (onSettingsUpdated != null) { + agent.addListener('updateHookSettings', onSettingsUpdated); + } agent.addListener('shutdown', () => { + if (onSettingsUpdated != null) { + agent.removeListener('updateHookSettings', onSettingsUpdated); + } + // If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down, // and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here. hook.emit('shutdown'); From d5e955d3c0c1fa2494de0ab33be9cd90c65aff1e Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 19 Sep 2024 10:07:29 -0400 Subject: [PATCH 174/426] [compiler] Pass through unmodified props spread when inlining jsx (#30995) If JSX receives a props spread without additional attributes (besides `ref` and `key`), we can pass the spread object as a property directly to avoid the extra object copy. ``` // {props: propsToSpread} // {props: {...propsToSpread, a: "z"}} ``` --- .../src/Optimization/InlineJsxTransform.ts | 63 ++++++++---- .../compiler/inline-jsx-transform.expect.md | 97 ++++++++++++------- .../fixtures/compiler/inline-jsx-transform.js | 11 ++- 3 files changed, 115 insertions(+), 56 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 344159d0b6072..0fe516da977e3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -23,6 +23,7 @@ import { markPredecessors, reversePostorderBlocks, } from '../HIR/HIRBuilder'; +import {CompilerError} from '..'; function createSymbolProperty( fn: HIRFunction, @@ -151,6 +152,16 @@ function createPropsProperties( let refProperty: ObjectProperty | undefined; let keyProperty: ObjectProperty | undefined; const props: Array = []; + const jsxAttributesWithoutKeyAndRef = propAttributes.filter( + p => p.kind === 'JsxAttribute' && p.name !== 'key' && p.name !== 'ref', + ); + const jsxSpreadAttributes = propAttributes.filter( + p => p.kind === 'JsxSpreadAttribute', + ); + const spreadPropsOnly = + jsxAttributesWithoutKeyAndRef.length === 0 && + jsxSpreadAttributes.length === 1; + propAttributes.forEach(prop => { switch (prop.kind) { case 'JsxAttribute': { @@ -180,7 +191,6 @@ function createPropsProperties( break; } case 'JsxSpreadAttribute': { - // TODO: Optimize spreads to pass object directly if none of its properties are mutated props.push({ kind: 'Spread', place: {...prop.argument}, @@ -189,6 +199,7 @@ function createPropsProperties( } } }); + const propsPropertyPlace = createTemporaryPlace(fn.env, instr.value.loc); if (children) { let childrenPropProperty: ObjectProperty; @@ -268,23 +279,39 @@ function createPropsProperties( nextInstructions.push(keyInstruction); } - const propsInstruction: Instruction = { - id: makeInstructionId(0), - lvalue: {...propsPropertyPlace, effect: Effect.Mutate}, - value: { - kind: 'ObjectExpression', - properties: props, - loc: instr.value.loc, - }, - loc: instr.loc, - }; - const propsProperty: ObjectProperty = { - kind: 'ObjectProperty', - key: {name: 'props', kind: 'string'}, - type: 'property', - place: {...propsPropertyPlace, effect: Effect.Capture}, - }; - nextInstructions.push(propsInstruction); + let propsProperty: ObjectProperty; + if (spreadPropsOnly) { + const spreadProp = jsxSpreadAttributes[0]; + CompilerError.invariant(spreadProp.kind === 'JsxSpreadAttribute', { + reason: 'Spread prop attribute must be of kind JSXSpreadAttribute', + loc: instr.loc, + }); + propsProperty = { + kind: 'ObjectProperty', + key: {name: 'props', kind: 'string'}, + type: 'property', + place: {...spreadProp.argument, effect: Effect.Mutate}, + }; + } else { + const propsInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...propsPropertyPlace, effect: Effect.Mutate}, + value: { + kind: 'ObjectExpression', + properties: props, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + propsProperty = { + kind: 'ObjectProperty', + key: {name: 'props', kind: 'string'}, + type: 'property', + place: {...propsPropertyPlace, effect: Effect.Capture}, + }; + nextInstructions.push(propsInstruction); + } + return {refProperty, keyProperty, propsProperty}; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md index f399317925c64..6dd899d5c7408 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -28,9 +28,9 @@ function ParentAndRefAndKey(props) { function ParentAndChildren(props) { return ( - + - + ); @@ -38,7 +38,12 @@ function ParentAndChildren(props) { const propsToSpread = {a: 'a', b: 'b', c: 'c'}; function PropsSpread() { - return ; + return ( + <> + + + + ); } export const FIXTURE_ENTRYPOINT = { @@ -146,54 +151,59 @@ function ParentAndRefAndKey(props) { } function ParentAndChildren(props) { - const $ = _c2(3); + const $ = _c2(7); let t0; - if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + if ($[0] !== props) { t0 = { $$typeof: Symbol.for("react.transitional.element"), type: Child, ref: null, key: "a", - props: {}, + props: props, }; - $[0] = t0; + $[0] = props; + $[1] = t0; } else { - t0 = $[0]; + t0 = $[1]; } let t1; - if ($[1] !== props.foo) { + if ($[2] !== props) { t1 = { $$typeof: Symbol.for("react.transitional.element"), - type: Parent, + type: Child, ref: null, - key: null, + key: "b", props: { - children: [ - t0, - { - $$typeof: Symbol.for("react.transitional.element"), - type: Child, - ref: null, - key: "b", - props: { - children: { - $$typeof: Symbol.for("react.transitional.element"), - type: GrandChild, - ref: null, - key: null, - props: { className: props.foo }, - }, - }, - }, - ], + children: { + $$typeof: Symbol.for("react.transitional.element"), + type: GrandChild, + ref: null, + key: null, + props: { className: props.foo, ...props }, + }, }, }; - $[1] = props.foo; - $[2] = t1; + $[2] = props; + $[3] = t1; } else { - t1 = $[2]; + t1 = $[3]; } - return t1; + let t2; + if ($[4] !== t0 || $[5] !== t1) { + t2 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Parent, + ref: null, + key: null, + props: { children: [t0, t1] }, + }; + $[4] = t0; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; } const propsToSpread = { a: "a", b: "b", c: "c" }; @@ -203,10 +213,27 @@ function PropsSpread() { if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = { $$typeof: Symbol.for("react.transitional.element"), - type: Test, + type: Symbol.for("react.fragment"), ref: null, key: null, - props: { ...propsToSpread }, + props: { + children: [ + { + $$typeof: Symbol.for("react.transitional.element"), + type: Test, + ref: null, + key: null, + props: propsToSpread, + }, + { + $$typeof: Symbol.for("react.transitional.element"), + type: Test, + ref: null, + key: null, + props: { ...propsToSpread, a: "z" }, + }, + ], + }, }; $[0] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js index 29acaf60d276f..4a9d53b6f4b96 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js @@ -24,9 +24,9 @@ function ParentAndRefAndKey(props) { function ParentAndChildren(props) { return ( - + - + ); @@ -34,7 +34,12 @@ function ParentAndChildren(props) { const propsToSpread = {a: 'a', b: 'b', c: 'c'}; function PropsSpread() { - return ; + return ( + <> + + + + ); } export const FIXTURE_ENTRYPOINT = { From 632f88df11329c9ad66781ddd75b27df6f8effb9 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 19 Sep 2024 10:34:24 -0400 Subject: [PATCH 175/426] [compiler] Allow ReactElement symbol to be configured when inlining jsx (#30996) Based on https://github.com/facebook/react/pull/30995 ([rendered diff](https://github.com/jackpope/react/compare/inline-jsx-2...jackpope:react:inline-jsx-3?expand=1)) ____ Some apps still use `react.element` symbols. Not only do we want to test there but we also want to be able to upgrade those sites to `react.transitional.element` without blocking on the compiler (we can change the symbol feature flag and compiler config at the same time). The compiler runtime uses `react.transitional.element`, so the snap fixture will fail if we change the default here. However I confirmed that commenting out the fixture entrypoint and running snap with `react.element` will update the fixture symbols as expected. --- .../src/Entrypoint/Pipeline.ts | 4 ++-- .../src/HIR/Environment.ts | 11 +++++++++- .../src/Optimization/InlineJsxTransform.ts | 21 ++++++++----------- compiler/packages/snap/src/compiler.ts | 7 +++++++ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 606440b241f9b..900e4f4908494 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -352,8 +352,8 @@ function* runWithEnvironment( }); } - if (env.config.enableInlineJsxTransform) { - inlineJsxTransform(hir); + if (env.config.inlineJsxTransform) { + inlineJsxTransform(hir, env.config.inlineJsxTransform); yield log({ kind: 'hir', name: 'inlineJsxTransform', diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 66270345fdf35..50905bc581dc1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -50,6 +50,13 @@ import { import {Scope as BabelScope} from '@babel/traverse'; import {TypeSchema} from './TypeSchema'; +export const ReactElementSymbolSchema = z.object({ + elementSymbol: z.union([ + z.literal('react.element'), + z.literal('react.transitional.element'), + ]), +}); + export const ExternalFunctionSchema = z.object({ // Source for the imported module that exports the `importSpecifierName` functions source: z.string(), @@ -237,8 +244,10 @@ const EnvironmentConfigSchema = z.object({ * Enables inlining ReactElement object literals in place of JSX * An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime * Currently a prod-only optimization, requiring Fast JSX dependencies + * + * The symbol configuration is set for backwards compatability with pre-React 19 transforms */ - enableInlineJsxTransform: z.boolean().default(false), + inlineJsxTransform: ReactElementSymbolSchema.nullish(), /* * Enable validation of hooks to partially check that the component honors the rules of hooks. diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 0fe516da977e3..396e6ad1be8dc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -23,7 +23,7 @@ import { markPredecessors, reversePostorderBlocks, } from '../HIR/HIRBuilder'; -import {CompilerError} from '..'; +import {CompilerError, EnvironmentConfig} from '..'; function createSymbolProperty( fn: HIRFunction, @@ -316,7 +316,12 @@ function createPropsProperties( } // TODO: Make PROD only with conditional statements -export function inlineJsxTransform(fn: HIRFunction): void { +export function inlineJsxTransform( + fn: HIRFunction, + inlineJsxTransformConfig: NonNullable< + EnvironmentConfig['inlineJsxTransform'] + >, +): void { for (const [, block] of fn.body.blocks) { let nextInstructions: Array | null = null; for (let i = 0; i < block.instructions.length; i++) { @@ -344,11 +349,7 @@ export function inlineJsxTransform(fn: HIRFunction): void { instr, nextInstructions, '$$typeof', - /** - * TODO: Add this to config so we can switch between - * react.element / react.transitional.element - */ - 'react.transitional.element', + inlineJsxTransformConfig.elementSymbol, ), createTagProperty(fn, instr, nextInstructions, instr.value.tag), refProperty, @@ -384,11 +385,7 @@ export function inlineJsxTransform(fn: HIRFunction): void { instr, nextInstructions, '$$typeof', - /** - * TODO: Add this to config so we can switch between - * react.element / react.transitional.element - */ - 'react.transitional.element', + inlineJsxTransformConfig.elementSymbol, ), createSymbolProperty( fn, diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index 417a657d28012..bbb6aeded750c 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -21,6 +21,7 @@ import type { } from 'babel-plugin-react-compiler/src/Entrypoint'; import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR'; import type { + EnvironmentConfig, Macro, MacroMethod, parseConfigPragma as ParseConfigPragma, @@ -201,6 +202,11 @@ function makePluginOptions( }; } + let inlineJsxTransform: EnvironmentConfig['inlineJsxTransform'] = null; + if (firstLine.includes('@enableInlineJsxTransform')) { + inlineJsxTransform = {elementSymbol: 'react.transitional.element'}; + } + let logs: Array<{filename: string | null; event: LoggerEvent}> = []; let logger: Logger | null = null; if (firstLine.includes('@logger')) { @@ -230,6 +236,7 @@ function makePluginOptions( enableChangeDetectionForDebugging, lowerContextAccess, validateBlocklistedImports, + inlineJsxTransform, }, compilationMode, logger, From c21ce4a39667c4094208bc35dc86fc9f49fceec6 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 19 Sep 2024 15:44:34 +0100 Subject: [PATCH 176/426] feat: display message if user ended up opening hook script (#31000) In https://github.com/facebook/react/pull/30596 we've moved console patching to the global hook. Generally speaking, the patching happens even before React is loaded on the page. If browser DevTools were opened after when `console.error` or `console.warn` were called, the source script will be `hook.js`, because of the patching. ![devtools-opened-after-the-message](https://github.com/user-attachments/assets/3d3dbc16-96b8-4234-b061-57b21b60cf2e) This is because ignore listing is not applied retroactively by Chrome DevTools. If you had it open before console calls, Hook script would be correctly filtered out from the stack: ![devtools-opened-before-the-message](https://github.com/user-attachments/assets/3e99cb22-97b0-4b49-9a76-f7bc948e6452) I had hopes that the fix for https://issues.chromium.org/issues/345248263 will also apply ignore listing retroactively, but looks like we need to open a separate feature request for the Chrome DevTools team. With these changes, if user attempts to open `hook.js` script, they are going to see this message: ![Screenshot 2024-09-19 at 11 30 59](https://github.com/user-attachments/assets/5850b74c-329f-4fbe-a3dd-33f9ac717ee9) --- .../webpack.config.js | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js index e6d40a1f20ad2..51b8f4e2105e3 100644 --- a/packages/react-devtools-extensions/webpack.config.js +++ b/packages/react-devtools-extensions/webpack.config.js @@ -154,6 +154,62 @@ module.exports = { ); }, }), + { + apply(compiler) { + if (__DEV__) { + return; + } + + const {RawSource} = compiler.webpack.sources; + compiler.hooks.compilation.tap( + 'CustomContentForHookScriptPlugin', + compilation => { + compilation.hooks.processAssets.tap( + { + name: 'CustomContentForHookScriptPlugin', + stage: Webpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING, + additionalAssets: true, + }, + assets => { + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const [name, asset] of Object.entries(assets)) { + if (name !== 'installHook.js.map') { + continue; + } + + const mapContent = asset.source().toString(); + if (!mapContent) { + continue; + } + + const map = JSON.parse(mapContent); + map.sourcesContent = map.sources.map(sourceName => { + if (!sourceName.endsWith('/hook.js')) { + return null; + } + + return ( + '/*\n' + + ' * This script is from React DevTools.\n' + + " * You're likely here because you thought it sent an error or warning to the console.\n" + + ' * React DevTools patches the console to support features like appending component stacks, \n' + + ' * so this file appears as a source. However, the console call actually came from another script.\n' + + " * To remove this script from stack traces, open your browser's DevTools (to enable source mapping) before these console calls happen.\n" + + ' */' + ); + }); + + compilation.updateAsset( + name, + new RawSource(JSON.stringify(map)), + ); + } + }, + ); + }, + ); + }, + }, ], module: { defaultRules: [ From e740d4b14b27b4c7a21f67d20a4526a57d6729a7 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 19 Sep 2024 15:47:25 +0100 Subject: [PATCH 177/426] chore: remove using local storage for persisting console settings on the frontend (#31002) After https://github.com/facebook/react/pull/30636 and https://github.com/facebook/react/pull/30986 we no longer store settings on the Frontend side via `localStorage`. This PR removes all occurrences of it from `react-devtools-core/standalone` and `react-devtools-inline`. --- .../react-devtools-core/src/standalone.js | 20 +------ .../react-devtools-inline/src/frontend.js | 12 +---- packages/react-devtools-shared/src/bridge.js | 4 -- .../react-devtools-shared/src/constants.js | 8 --- .../views/Settings/SettingsModalContext.js | 1 - packages/react-devtools-shared/src/utils.js | 52 ------------------- 6 files changed, 2 insertions(+), 95 deletions(-) diff --git a/packages/react-devtools-core/src/standalone.js b/packages/react-devtools-core/src/standalone.js index 22aea529dd8e3..bfd05cf5227ee 100644 --- a/packages/react-devtools-core/src/standalone.js +++ b/packages/react-devtools-core/src/standalone.js @@ -12,13 +12,7 @@ import {flushSync} from 'react-dom'; import {createRoot} from 'react-dom/client'; import Bridge from 'react-devtools-shared/src/bridge'; import Store from 'react-devtools-shared/src/devtools/store'; -import { - getAppendComponentStack, - getBreakOnConsoleErrors, - getSavedComponentFilters, - getShowInlineWarningsAndErrors, - getHideConsoleLogsInStrictMode, -} from 'react-devtools-shared/src/utils'; +import {getSavedComponentFilters} from 'react-devtools-shared/src/utils'; import {registerDevToolsEventLogger} from 'react-devtools-shared/src/registerDevToolsEventLogger'; import {Server} from 'ws'; import {join} from 'path'; @@ -368,20 +362,8 @@ function startServer( // Because of this it relies on the extension to pass filters, so include them wth the response here. // This will ensure that saved filters are shared across different web pages. const savedPreferencesString = ` - window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = ${JSON.stringify( - getAppendComponentStack(), - )}; - window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ = ${JSON.stringify( - getBreakOnConsoleErrors(), - )}; window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = ${JSON.stringify( getSavedComponentFilters(), - )}; - window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ = ${JSON.stringify( - getShowInlineWarningsAndErrors(), - )}; - window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ = ${JSON.stringify( - getHideConsoleLogsInStrictMode(), )};`; response.end( diff --git a/packages/react-devtools-inline/src/frontend.js b/packages/react-devtools-inline/src/frontend.js index 9031f6ffc7bd7..f96d29ac50745 100644 --- a/packages/react-devtools-inline/src/frontend.js +++ b/packages/react-devtools-inline/src/frontend.js @@ -5,13 +5,7 @@ import {forwardRef} from 'react'; import Bridge from 'react-devtools-shared/src/bridge'; import Store from 'react-devtools-shared/src/devtools/store'; import DevTools from 'react-devtools-shared/src/devtools/views/DevTools'; -import { - getAppendComponentStack, - getBreakOnConsoleErrors, - getSavedComponentFilters, - getShowInlineWarningsAndErrors, - getHideConsoleLogsInStrictMode, -} from 'react-devtools-shared/src/utils'; +import {getSavedComponentFilters} from 'react-devtools-shared/src/utils'; import type {Wall} from 'react-devtools-shared/src/frontend/types'; import type {FrontendBridge} from 'react-devtools-shared/src/bridge'; @@ -76,11 +70,7 @@ export function initialize( frontendBridge.removeListener('getSavedPreferences', onGetSavedPreferences); const data = { - appendComponentStack: getAppendComponentStack(), - breakOnConsoleErrors: getBreakOnConsoleErrors(), componentFilters: getSavedComponentFilters(), - showInlineWarningsAndErrors: getShowInlineWarningsAndErrors(), - hideConsoleLogsInStrictMode: getHideConsoleLogsInStrictMode(), }; // The renderer interface can't read saved preferences directly, diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index 4751f70cfaefb..fcf9b2d21e88d 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -170,11 +170,7 @@ type NativeStyleEditor_SetValueParams = { }; type SavedPreferencesParams = { - appendComponentStack: boolean, - breakOnConsoleErrors: boolean, componentFilters: Array, - showInlineWarningsAndErrors: boolean, - hideConsoleLogsInStrictMode: boolean, }; export type BackendEvents = { diff --git a/packages/react-devtools-shared/src/constants.js b/packages/react-devtools-shared/src/constants.js index 52d39f2d90b07..6893610b46d8f 100644 --- a/packages/react-devtools-shared/src/constants.js +++ b/packages/react-devtools-shared/src/constants.js @@ -43,17 +43,9 @@ export const SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY = 'React::DevTools::recordChangeDescriptions'; export const SESSION_STORAGE_RELOAD_AND_PROFILE_KEY = 'React::DevTools::reloadAndProfile'; -export const LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS = - 'React::DevTools::breakOnConsoleErrors'; export const LOCAL_STORAGE_BROWSER_THEME = 'React::DevTools::theme'; -export const LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY = - 'React::DevTools::appendComponentStack'; -export const LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY = - 'React::DevTools::showInlineWarningsAndErrors'; export const LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY = 'React::DevTools::traceUpdatesEnabled'; -export const LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE = - 'React::DevTools::hideConsoleLogsInStrictMode'; export const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY = 'React::DevTools::supportsProfiling'; diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js index 98e491f44b6eb..f8f76053fc129 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContext.js @@ -24,7 +24,6 @@ import type {FrontendBridge} from '../../../bridge'; import type {DevToolsHookSettings} from '../../../backend/types'; import type Store from '../../store'; -export type DisplayDensity = 'comfortable' | 'compact'; export type Theme = 'auto' | 'light' | 'dark'; type Context = { diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 9b927c19219fb..e24414812c5b3 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -36,10 +36,6 @@ import { TREE_OPERATION_UPDATE_TREE_BASE_DURATION, LOCAL_STORAGE_COMPONENT_FILTER_PREFERENCES_KEY, LOCAL_STORAGE_OPEN_IN_EDITOR_URL, - LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS, - LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY, - LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY, - LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE, } from './constants'; import { ComponentFilterElementType, @@ -61,7 +57,6 @@ import isArray from './isArray'; import type { ComponentFilter, ElementType, - BrowserTheme, SerializedElement as SerializedElementFrontend, LRUCache, } from 'react-devtools-shared/src/frontend/types'; @@ -374,53 +369,6 @@ export function filterOutLocationComponentFilters( return componentFilters.filter(f => f.type !== ComponentFilterLocation); } -function parseBool(s: ?string): ?boolean { - if (s === 'true') { - return true; - } - if (s === 'false') { - return false; - } -} - -export function castBool(v: any): ?boolean { - if (v === true || v === false) { - return v; - } -} - -export function castBrowserTheme(v: any): ?BrowserTheme { - if (v === 'light' || v === 'dark' || v === 'auto') { - return v; - } -} - -export function getAppendComponentStack(): boolean { - const raw = localStorageGetItem( - LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY, - ); - return parseBool(raw) ?? true; -} - -export function getBreakOnConsoleErrors(): boolean { - const raw = localStorageGetItem(LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS); - return parseBool(raw) ?? false; -} - -export function getHideConsoleLogsInStrictMode(): boolean { - const raw = localStorageGetItem( - LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE, - ); - return parseBool(raw) ?? false; -} - -export function getShowInlineWarningsAndErrors(): boolean { - const raw = localStorageGetItem( - LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY, - ); - return parseBool(raw) ?? true; -} - export function getDefaultOpenInEditorURL(): string { return typeof process.env.EDITOR_URL === 'string' ? process.env.EDITOR_URL From babde5d1826365bfb794abdb7de4bd21f7b02356 Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 19 Sep 2024 13:42:49 -0400 Subject: [PATCH 178/426] [lint] Add no-optional-chaining (#31003) ## Overview Adds a lint rule to prevent optional chaining to catch issues like https://github.com/facebook/react/pull/30982 until we support optional chaining without a bundle impact. --- .eslintrc.js | 4 +++- package.json | 1 + packages/react-debug-tools/src/ReactDebugHooks.js | 5 +++-- yarn.lock | 10 +++++++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index ed134392a9727..3366a38517c93 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,6 +23,7 @@ module.exports = { 'babel', 'ft-flow', 'jest', + 'es', 'no-for-of-loops', 'no-function-declare-after-return', 'react', @@ -47,7 +48,7 @@ module.exports = { 'ft-flow/no-unused-expressions': ERROR, // 'ft-flow/no-weak-types': WARNING, // 'ft-flow/require-valid-file-annotation': ERROR, - + 'es/no-optional-chaining': ERROR, 'no-cond-assign': OFF, 'no-constant-condition': OFF, 'no-control-regex': OFF, @@ -435,6 +436,7 @@ module.exports = { 'packages/react-dom/src/test-utils/*.js', ], rules: { + 'es/no-optional-chaining': OFF, 'react-internal/no-production-logging': OFF, 'react-internal/warning-args': OFF, 'react-internal/safe-string-coercion': [ diff --git a/package.json b/package.json index f840fc278e7be..cae8499738d22 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "eslint": "^7.7.0", "eslint-config-prettier": "^6.9.0", "eslint-plugin-babel": "^5.3.0", + "eslint-plugin-es": "^4.1.0", "eslint-plugin-eslint-plugin": "^3.5.3", "eslint-plugin-ft-flow": "^2.0.3", "eslint-plugin-jest": "28.4.0", diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 55a1454142235..44d684003861b 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -567,8 +567,9 @@ function useMemoCache(size: number): Array { return []; } - // $FlowFixMe[incompatible-use]: updateQueue is mixed - const memoCache = fiber.updateQueue?.memoCache; + const memoCache = + // $FlowFixMe[incompatible-use]: updateQueue is mixed + fiber.updateQueue != null ? fiber.updateQueue.memoCache : null; if (memoCache == null) { return []; } diff --git a/yarn.lock b/yarn.lock index bf4f7825f6997..b23f0d92aebfc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7262,6 +7262,14 @@ eslint-plugin-babel@^5.3.0: dependencies: eslint-rule-composer "^0.3.0" +eslint-plugin-es@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9" + integrity sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + eslint-plugin-eslint-plugin@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-3.5.3.tgz#6cac958e944b820962a4cf9e65cc32a2e0415eaf" @@ -13971,7 +13979,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^3.1.0: +regexpp@^3.0.0, regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== From e4953922a99b5477c3bcf98cdaa2b13ac0a81f0d Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 19 Sep 2024 18:04:06 -0400 Subject: [PATCH 179/426] Update react-native/react-dom build directory (#31006) Commit artifact actions are breaking after https://github.com/facebook/react/pull/30711 See: https://github.com/facebook/react/actions/runs/10930658977/job/30344033974 > mv: cannot stat 'build/facebook-react-native/react/dom/': No such file or directory After build, the new artifacts are in `/react-dom/cjs`, not `/react/dom/` ``` $> yarn build $> ls build/facebook-react-native/react/ # ... no dom $> ls build/facebook-react-native/react-dom/cjs ``` --- .github/workflows/runtime_commit_artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index ed0c59caf883e..2baabaf59f5c5 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -125,7 +125,7 @@ jobs: mv build/react-native/shims/ $BASE_FOLDER/react-native-github/Libraries/Renderer/ mv build/facebook-react-native/scheduler/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/scheduler/ mv build/facebook-react-native/react/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react/ - mv build/facebook-react-native/react/dom/ $BASE_FOLDER/RKJSModules/vendor/react/react-dom/ + mv build/facebook-react-native/react-dom/cjs $BASE_FOLDER/RKJSModules/vendor/react/react-dom/ mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/ mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/ From ae75d5a3f5cf14a5031ee251376b1adf88c32813 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 20 Sep 2024 10:00:02 -0700 Subject: [PATCH 180/426] [Fizz] Include componentStack at the root when aborting (#31011) When aborting we currently don't produce a componentStack when aborting the shell. This is likely just an oversight and this change updates this behavior to be consistent with what we do when there is a boundary --- packages/react-server/src/ReactFizzServer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index d0e6eb852c08f..0f863d24b9c57 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -3870,8 +3870,9 @@ function abortTask(task: Task, request: Request, error: mixed): void { segment.status = ABORTED; } + const errorInfo = getThrownInfo(task.componentStack); + if (boundary === null) { - const errorInfo: ThrownInfo = {}; if (request.status !== CLOSING && request.status !== CLOSED) { const replay: null | ReplaySet = task.replay; if (replay === null) { @@ -3957,7 +3958,6 @@ function abortTask(task: Task, request: Request, error: mixed): void { boundary.pendingTasks--; // We construct an errorInfo from the boundary's componentStack so the error in dev will indicate which // boundary the message is referring to - const errorInfo = getThrownInfo(task.componentStack); const trackedPostpones = request.trackedPostpones; if (boundary.status !== CLIENT_RENDERED) { if (enableHalt) { From d4688dfaafe51a4cb6e3c51fc2330662cb4e2296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 20 Sep 2024 14:27:12 -0400 Subject: [PATCH 181/426] [Fiber] Track Event Time, startTransition Time and setState Time (#31008) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This tracks the current window.event.timeStamp the first time we setState or call startTransition. For either the blocking track or transition track. We can use this to show how long we were blocked by other events or overhead from when the user interacted until we got called into React. Then we track the time we start awaiting a Promise returned from startTransition. We can use this track how long we waited on an Action to complete before setState was called. Then finally we track when setState was called so we can track how long we were blocked by other word before we could actually start rendering. For a Transition this might be blocked by Blocking React render work. We only log these once a subsequent render actually happened. If no render was actually scheduled, then we don't log these. E.g. if an isomorphic Action doesn't call startTransition there's no render so we don't log it. We only log the first event/update/transition even if multiple are batched into it later. If multiple Actions are entangled they're all treated as one until an update happens. If no update happens and all entangled actions finish, we clear the transition so that the next time a new sequence starts we can log it. We also clamp these (start the track later) if they were scheduled within a render/commit. Since we share a single track we don't want to create overlapping tracks. The purpose of this is not to show every event/action that happens but to show a prelude to how long we were blocked before a render started. So you can follow the first event to commit. Screenshot 2024-09-20 at 1 59 58 AM I still need to add the rendering/suspended phases to the timeline which why this screenshot has a gap. Screenshot 2024-09-20 at 12 50 27 AM In this case it's a Form Action which started a render into the form which then suspended on the action. The action then caused a refresh, which interrupts with its own update that's blocked before rendering. Suspended roots like this is interesting because we could in theory start working on a different root in the meantime which makes this timeline less linear. --- packages/react-art/src/ReactFiberConfigART.js | 8 ++ .../src/client/ReactFiberConfigDOM.js | 10 ++ .../src/ReactFiberConfigFabric.js | 8 ++ .../src/ReactFiberConfigNative.js | 8 ++ .../src/createReactNoop.js | 8 ++ .../src/ReactFiberAsyncAction.js | 52 +++++--- .../src/ReactFiberClassComponent.js | 4 + .../react-reconciler/src/ReactFiberHooks.js | 69 ++++++++-- .../react-reconciler/src/ReactFiberLane.js | 17 +++ .../src/ReactFiberPerformanceTrack.js | 65 ++++++++++ .../src/ReactFiberReconciler.js | 2 + .../src/ReactFiberTransition.js | 8 ++ .../src/ReactFiberWorkLoop.js | 70 +++++++++++ .../src/ReactProfilerTimer.js | 119 ++++++++++++++++++ .../ReactFiberHostContext-test.internal.js | 6 + .../src/forks/ReactFiberConfig.custom.js | 2 + .../src/ReactFiberConfigTestHost.js | 7 ++ .../__tests__/ReactProfiler-test.internal.js | 6 + 18 files changed, 443 insertions(+), 26 deletions(-) diff --git a/packages/react-art/src/ReactFiberConfigART.js b/packages/react-art/src/ReactFiberConfigART.js index 816353e0ced2f..33bbe055724d9 100644 --- a/packages/react-art/src/ReactFiberConfigART.js +++ b/packages/react-art/src/ReactFiberConfigART.js @@ -363,6 +363,14 @@ export function resolveUpdatePriority(): EventPriority { return currentUpdatePriority || DefaultEventPriority; } +export function resolveEventType(): null | string { + return null; +} + +export function resolveEventTimeStamp(): number { + return -1.1; +} + export function shouldAttemptEagerTransition() { return false; } diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 0e39f988f813c..d46f61035b8d4 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -606,6 +606,16 @@ export function shouldAttemptEagerTransition(): boolean { return false; } +export function resolveEventType(): null | string { + const event = window.event; + return event ? event.type : null; +} + +export function resolveEventTimeStamp(): number { + const event = window.event; + return event ? event.timeStamp : -1.1; +} + export const isPrimaryRenderer = true; export const warnsIfNotActing = true; // This initialization code may run even on server environments diff --git a/packages/react-native-renderer/src/ReactFiberConfigFabric.js b/packages/react-native-renderer/src/ReactFiberConfigFabric.js index 80215d11ec14c..10f7c6ecd84a3 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigFabric.js +++ b/packages/react-native-renderer/src/ReactFiberConfigFabric.js @@ -372,6 +372,14 @@ export function resolveUpdatePriority(): EventPriority { return DefaultEventPriority; } +export function resolveEventType(): null | string { + return null; +} + +export function resolveEventTimeStamp(): number { + return -1.1; +} + export function shouldAttemptEagerTransition(): boolean { return false; } diff --git a/packages/react-native-renderer/src/ReactFiberConfigNative.js b/packages/react-native-renderer/src/ReactFiberConfigNative.js index 0a95e0f818cdb..1dc8c627b1ccb 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigNative.js +++ b/packages/react-native-renderer/src/ReactFiberConfigNative.js @@ -288,6 +288,14 @@ export function resolveUpdatePriority(): EventPriority { return DefaultEventPriority; } +export function resolveEventType(): null | string { + return null; +} + +export function resolveEventTimeStamp(): number { + return -1.1; +} + export function shouldAttemptEagerTransition(): boolean { return false; } diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 859bab499b6f3..55e0fd24c9b9b 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -533,6 +533,14 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { return currentEventPriority; }, + resolveEventType(): null | string { + return null; + }, + + resolveEventTimeStamp(): number { + return -1.1; + }, + shouldAttemptEagerTransition(): boolean { return false; }, diff --git a/packages/react-reconciler/src/ReactFiberAsyncAction.js b/packages/react-reconciler/src/ReactFiberAsyncAction.js index ec53c7d80346c..4d210d02ac827 100644 --- a/packages/react-reconciler/src/ReactFiberAsyncAction.js +++ b/packages/react-reconciler/src/ReactFiberAsyncAction.js @@ -17,6 +17,14 @@ import type {BatchConfigTransition} from './ReactFiberTracingMarkerComponent'; import {requestTransitionLane} from './ReactFiberRootScheduler'; import {NoLane} from './ReactFiberLane'; +import { + hasScheduledTransitionWork, + clearAsyncTransitionTimer, +} from './ReactProfilerTimer'; +import { + enableComponentPerformanceTrack, + enableProfilerTimer, +} from 'shared/ReactFeatureFlags'; // If there are multiple, concurrent async actions, they are entangled. All // transition updates that occur while the async action is still in progress @@ -64,24 +72,34 @@ export function entangleAsyncAction( } function pingEngtangledActionScope() { - if ( - currentEntangledListeners !== null && - --currentEntangledPendingCount === 0 - ) { - // All the actions have finished. Close the entangled async action scope - // and notify all the listeners. - if (currentEntangledActionThenable !== null) { - const fulfilledThenable: FulfilledThenable = - (currentEntangledActionThenable: any); - fulfilledThenable.status = 'fulfilled'; + if (--currentEntangledPendingCount === 0) { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + if (!hasScheduledTransitionWork()) { + // If we have received no updates since we started the entangled Actions + // that means it didn't lead to a Transition being rendered. We need to + // clear the timer so that if we start another entangled sequence we use + // the next start timer instead of appearing like we were blocked the + // whole time. We currently don't log a track for Actions that don't + // render a Transition. + clearAsyncTransitionTimer(); + } } - const listeners = currentEntangledListeners; - currentEntangledListeners = null; - currentEntangledLane = NoLane; - currentEntangledActionThenable = null; - for (let i = 0; i < listeners.length; i++) { - const listener = listeners[i]; - listener(); + if (currentEntangledListeners !== null) { + // All the actions have finished. Close the entangled async action scope + // and notify all the listeners. + if (currentEntangledActionThenable !== null) { + const fulfilledThenable: FulfilledThenable = + (currentEntangledActionThenable: any); + fulfilledThenable.status = 'fulfilled'; + } + const listeners = currentEntangledListeners; + currentEntangledListeners = null; + currentEntangledLane = NoLane; + currentEntangledActionThenable = null; + for (let i = 0; i < listeners.length; i++) { + const listener = listeners[i]; + listener(); + } } } } diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index f1419d1aad047..79c516eacf117 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -72,6 +72,7 @@ import { markStateUpdateScheduled, setIsStrictModeForDevtools, } from './ReactFiberDevToolsHook'; +import {startUpdateTimerByLane} from './ReactProfilerTimer'; const fakeInternalInstance = {}; @@ -194,6 +195,7 @@ const classComponentUpdater = { const root = enqueueUpdate(fiber, update, lane); if (root !== null) { + startUpdateTimerByLane(lane); scheduleUpdateOnFiber(root, fiber, lane); entangleTransitions(root, fiber, lane); } @@ -228,6 +230,7 @@ const classComponentUpdater = { const root = enqueueUpdate(fiber, update, lane); if (root !== null) { + startUpdateTimerByLane(lane); scheduleUpdateOnFiber(root, fiber, lane); entangleTransitions(root, fiber, lane); } @@ -262,6 +265,7 @@ const classComponentUpdater = { const root = enqueueUpdate(fiber, update, lane); if (root !== null) { + startUpdateTimerByLane(lane); scheduleUpdateOnFiber(root, fiber, lane); entangleTransitions(root, fiber, lane); } diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index 59d2f0f025610..77d3e985011de 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -131,6 +131,7 @@ import { markStateUpdateScheduled, setIsStrictModeForDevtools, } from './ReactFiberDevToolsHook'; +import {startUpdateTimerByLane} from './ReactProfilerTimer'; import {createCache} from './ReactFiberCacheComponent'; import { createUpdate as createLegacyQueueUpdate, @@ -3019,7 +3020,12 @@ function startTransition( dispatchOptimisticSetState(fiber, false, queue, pendingState); } else { ReactSharedInternals.T = null; - dispatchSetState(fiber, queue, pendingState); + dispatchSetStateInternal( + fiber, + queue, + pendingState, + requestUpdateLane(fiber), + ); ReactSharedInternals.T = currentTransition; } @@ -3062,13 +3068,28 @@ function startTransition( thenable, finishedState, ); - dispatchSetState(fiber, queue, (thenableForFinishedState: any)); + dispatchSetStateInternal( + fiber, + queue, + (thenableForFinishedState: any), + requestUpdateLane(fiber), + ); } else { - dispatchSetState(fiber, queue, finishedState); + dispatchSetStateInternal( + fiber, + queue, + finishedState, + requestUpdateLane(fiber), + ); } } else { // Async actions are not enabled. - dispatchSetState(fiber, queue, finishedState); + dispatchSetStateInternal( + fiber, + queue, + finishedState, + requestUpdateLane(fiber), + ); callback(); } } catch (error) { @@ -3081,7 +3102,12 @@ function startTransition( status: 'rejected', reason: error, }; - dispatchSetState(fiber, queue, rejectedThenable); + dispatchSetStateInternal( + fiber, + queue, + rejectedThenable, + requestUpdateLane(fiber), + ); } else { // The error rethrowing behavior is only enabled when the async actions // feature is on, even for sync actions. @@ -3253,7 +3279,12 @@ export function requestFormReset(formFiber: Fiber) { const newResetState = {}; const resetStateHook: Hook = (stateHook.next: any); const resetStateQueue = resetStateHook.queue; - dispatchSetState(formFiber, resetStateQueue, newResetState); + dispatchSetStateInternal( + formFiber, + resetStateQueue, + newResetState, + requestUpdateLane(formFiber), + ); } function mountTransition(): [ @@ -3385,6 +3416,7 @@ function refreshCache(fiber: Fiber, seedKey: ?() => T, seedValue: T): void { const refreshUpdate = createLegacyQueueUpdate(lane); const root = enqueueLegacyQueueUpdate(provider, refreshUpdate, lane); if (root !== null) { + startUpdateTimerByLane(lane); scheduleUpdateOnFiber(root, provider, lane); entangleLegacyQueueTransitions(root, provider, lane); } @@ -3450,6 +3482,7 @@ function dispatchReducerAction( } else { const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); if (root !== null) { + startUpdateTimerByLane(lane); scheduleUpdateOnFiber(root, fiber, lane); entangleTransitionUpdate(root, queue, lane); } @@ -3474,7 +3507,24 @@ function dispatchSetState( } const lane = requestUpdateLane(fiber); + const didScheduleUpdate = dispatchSetStateInternal( + fiber, + queue, + action, + lane, + ); + if (didScheduleUpdate) { + startUpdateTimerByLane(lane); + } + markUpdateInDevTools(fiber, lane, action); +} +function dispatchSetStateInternal( + fiber: Fiber, + queue: UpdateQueue, + action: A, + lane: Lane, +): boolean { const update: Update = { lane, revertLane: NoLane, @@ -3518,7 +3568,7 @@ function dispatchSetState( // time the reducer has changed. // TODO: Do we still need to entangle transitions in this case? enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update); - return; + return false; } } catch (error) { // Suppress the error. It will throw again in the render phase. @@ -3534,10 +3584,10 @@ function dispatchSetState( if (root !== null) { scheduleUpdateOnFiber(root, fiber, lane); entangleTransitionUpdate(root, queue, lane); + return true; } } - - markUpdateInDevTools(fiber, lane, action); + return false; } function dispatchOptimisticSetState( @@ -3619,6 +3669,7 @@ function dispatchOptimisticSetState( // will never be attempted before the optimistic update. This currently // holds because the optimistic update is always synchronous. If we ever // change that, we'll need to account for this. + startUpdateTimerByLane(SyncLane); scheduleUpdateOnFiber(root, fiber, SyncLane); // Optimistic updates are always synchronous, so we don't need to call // entangleTransitionUpdate here. diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index f72174e208555..b8c051def4eef 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -592,6 +592,10 @@ export function includesSyncLane(lanes: Lanes): boolean { return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; } +export function isSyncLane(lanes: Lanes): boolean { + return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; +} + export function includesNonIdleWork(lanes: Lanes): boolean { return (lanes & NonIdleLanes) !== NoLanes; } @@ -608,6 +612,10 @@ export function includesOnlyTransitions(lanes: Lanes): boolean { return (lanes & TransitionLanes) === lanes; } +export function includesTransitionLane(lanes: Lanes): boolean { + return (lanes & TransitionLanes) !== NoLanes; +} + export function includesBlockingLane(lanes: Lanes): boolean { const SyncDefaultLanes = InputContinuousHydrationLane | @@ -623,6 +631,15 @@ export function includesExpiredLane(root: FiberRoot, lanes: Lanes): boolean { return (lanes & root.expiredLanes) !== NoLanes; } +export function isBlockingLane(lane: Lane): boolean { + const SyncDefaultLanes = + InputContinuousHydrationLane | + InputContinuousLane | + DefaultHydrationLane | + DefaultLane; + return (lane & SyncDefaultLanes) !== NoLanes; +} + export function isTransitionLane(lane: Lane): boolean { return (lane & TransitionLanes) !== NoLanes; } diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index a053ea56ffc7f..94a7ec458fc57 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -99,3 +99,68 @@ export function logComponentEffect( performance.measure(name, reusableComponentOptions); } } + +export function logBlockingStart( + updateTime: number, + eventTime: number, + eventType: null | string, + renderStartTime: number, +): void { + if (supportsUserTiming) { + reusableComponentDevToolDetails.track = 'Blocking'; + if (eventTime > 0 && eventType !== null) { + // Log the time from the event timeStamp until we called setState. + reusableComponentDevToolDetails.color = 'secondary-dark'; + reusableComponentOptions.start = eventTime; + reusableComponentOptions.end = + updateTime > 0 ? updateTime : renderStartTime; + performance.measure(eventType, reusableComponentOptions); + } + if (updateTime > 0) { + // Log the time from when we called setState until we started rendering. + reusableComponentDevToolDetails.color = 'primary-light'; + reusableComponentOptions.start = updateTime; + reusableComponentOptions.end = renderStartTime; + performance.measure('Blocked', reusableComponentOptions); + } + } +} + +export function logTransitionStart( + startTime: number, + updateTime: number, + eventTime: number, + eventType: null | string, + renderStartTime: number, +): void { + if (supportsUserTiming) { + reusableComponentDevToolDetails.track = 'Transition'; + if (eventTime > 0 && eventType !== null) { + // Log the time from the event timeStamp until we started a transition. + reusableComponentDevToolDetails.color = 'secondary-dark'; + reusableComponentOptions.start = eventTime; + reusableComponentOptions.end = + startTime > 0 + ? startTime + : updateTime > 0 + ? updateTime + : renderStartTime; + performance.measure(eventType, reusableComponentOptions); + } + if (startTime > 0) { + // Log the time from when we started an async transition until we called setState or started rendering. + reusableComponentDevToolDetails.color = 'primary-dark'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = + updateTime > 0 ? updateTime : renderStartTime; + performance.measure('Action', reusableComponentOptions); + } + if (updateTime > 0) { + // Log the time from when we called setState until we started rendering. + reusableComponentDevToolDetails.color = 'primary-light'; + reusableComponentOptions.start = updateTime; + reusableComponentOptions.end = renderStartTime; + performance.measure('Blocked', reusableComponentOptions); + } + } +} diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index 9a200b4e4feb4..94f1397eb129e 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -61,6 +61,7 @@ import { onScheduleRoot, injectProfilingHooks, } from './ReactFiberDevToolsHook'; +import {startUpdateTimerByLane} from './ReactProfilerTimer'; import { requestUpdateLane, scheduleUpdateOnFiber, @@ -433,6 +434,7 @@ function updateContainerImpl( const root = enqueueUpdate(rootFiber, update, lane); if (root !== null) { + startUpdateTimerByLane(lane); scheduleUpdateOnFiber(root, rootFiber, lane); entangleTransitions(root, rootFiber, lane); } diff --git a/packages/react-reconciler/src/ReactFiberTransition.js b/packages/react-reconciler/src/ReactFiberTransition.js index c378beee30d3b..8ddd7083363a8 100644 --- a/packages/react-reconciler/src/ReactFiberTransition.js +++ b/packages/react-reconciler/src/ReactFiberTransition.js @@ -35,6 +35,7 @@ import { import ReactSharedInternals from 'shared/ReactSharedInternals'; import {entangleAsyncAction} from './ReactFiberAsyncAction'; +import {startAsyncTransitionTimer} from './ReactProfilerTimer'; export const NoTransition = null; @@ -69,6 +70,13 @@ ReactSharedInternals.S = function onStartTransitionFinishForReconciler( returnValue !== null && typeof returnValue.then === 'function' ) { + // If we're going to wait on some async work before scheduling an update. + // We mark the time so we can later log how long we were blocked on the Action. + // Ideally, we'd include the sync part of the action too but since that starts + // in isomorphic code it currently leads to tricky layering. We'd have to pass + // in performance.now() to this callback but we sometimes use a polyfill. + startAsyncTransitionTimer(); + // This is an async action const thenable: Thenable = (returnValue: any); entangleAsyncAction(transition, thenable); diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index dba089e81f3e0..b576309dc84ab 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -68,6 +68,10 @@ import { logRenderStarted, logRenderStopped, } from './DebugTracing'; +import { + logBlockingStart, + logTransitionStart, +} from './ReactFiberPerformanceTrack'; import { resetAfterCommit, @@ -145,6 +149,7 @@ import { includesOnlyRetries, includesOnlyTransitions, includesBlockingLane, + includesTransitionLane, includesExpiredLane, getNextLanes, getEntangledLanes, @@ -221,7 +226,20 @@ import { } from './ReactFiberConcurrentUpdates'; import { + blockingUpdateTime, + blockingEventTime, + blockingEventType, + transitionStartTime, + transitionUpdateTime, + transitionEventTime, + transitionEventType, + clearBlockingTimers, + clearTransitionTimers, + clampBlockingTimers, + clampTransitionTimers, markNestedUpdateScheduled, + renderStartTime, + recordRenderTime, recordCompleteTime, recordCommitTime, resetNestedUpdateFlag, @@ -1698,7 +1716,48 @@ function resetWorkInProgressStack() { workInProgress = null; } +function finalizeRender(lanes: Lanes, finalizationTime: number): void { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + if (includesSyncLane(lanes) || includesBlockingLane(lanes)) { + clampBlockingTimers(finalizationTime); + } + if (includesTransitionLane(lanes)) { + clampTransitionTimers(finalizationTime); + } + } +} + function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // Starting a new render. Log the end of any previous renders and the + // blocked time before the render started. + recordRenderTime(); + // If this was a restart, e.g. due to an interrupting update, then there's no space + // in the track to log the cause since we'll have rendered all the way up until the + // restart so we need to clamp that. + finalizeRender(workInProgressRootRenderLanes, renderStartTime); + + if (includesSyncLane(lanes) || includesBlockingLane(lanes)) { + logBlockingStart( + blockingUpdateTime, + blockingEventTime, + blockingEventType, + renderStartTime, + ); + clearBlockingTimers(); + } + if (includesTransitionLane(lanes)) { + logTransitionStart( + transitionStartTime, + transitionUpdateTime, + transitionEventTime, + transitionEventType, + renderStartTime, + ); + clearTransitionTimers(); + } + } + root.finishedWork = null; root.finishedLanes = NoLanes; @@ -2240,6 +2299,7 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) { } workInProgressTransitions = getTransitionsForLanes(root, lanes); + resetRenderTimer(); prepareFreshStack(root, lanes); } else { @@ -3358,6 +3418,12 @@ function commitRootImpl( nestedUpdateCount = 0; } + if (enableProfilerTimer && enableComponentPerformanceTrack) { + if (!rootDidHavePassiveEffects) { + finalizeRender(lanes, now()); + } + } + // If layout work was scheduled, flush it now. flushSyncWorkOnAllRoots(); @@ -3539,6 +3605,10 @@ function flushPassiveEffectsImpl() { executionContext = prevExecutionContext; + if (enableProfilerTimer && enableComponentPerformanceTrack) { + finalizeRender(lanes, now()); + } + flushSyncWorkOnAllRoots(); if (enableTransitionTracing) { diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index d65ca0a7544ee..cf3133524813e 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -9,10 +9,16 @@ import type {Fiber} from './ReactInternalTypes'; +import type {Lane} from './ReactFiberLane'; +import {isTransitionLane, isBlockingLane, isSyncLane} from './ReactFiberLane'; + +import {resolveEventType, resolveEventTimeStamp} from './ReactFiberConfig'; + import { enableProfilerCommitHooks, enableProfilerNestedUpdatePhase, enableProfilerTimer, + enableComponentPerformanceTrack, } from 'shared/ReactFeatureFlags'; // Intentionally not named imports because Rollup would use dynamic dispatch for @@ -21,6 +27,7 @@ import * as Scheduler from 'scheduler'; const {unstable_now: now} = Scheduler; +export let renderStartTime: number = -0; export let completeTime: number = -0; export let commitTime: number = -0; export let profilerStartTime: number = -1.1; @@ -29,6 +36,111 @@ export let componentEffectDuration: number = -0; export let componentEffectStartTime: number = -1.1; export let componentEffectEndTime: number = -1.1; +export let blockingUpdateTime: number = -1.1; // First sync setState scheduled. +export let blockingEventTime: number = -1.1; // Event timeStamp of the first setState. +export let blockingEventType: null | string = null; // Event type of the first setState. +// TODO: This should really be one per Transition lane. +export let transitionStartTime: number = -1.1; // First startTransition call before setState. +export let transitionUpdateTime: number = -1.1; // First transition setState scheduled. +export let transitionEventTime: number = -1.1; // Event timeStamp of the first transition. +export let transitionEventType: null | string = null; // Event type of the first transition. + +export function startUpdateTimerByLane(lane: Lane): void { + if (!enableProfilerTimer || !enableComponentPerformanceTrack) { + return; + } + if (isSyncLane(lane) || isBlockingLane(lane)) { + if (blockingUpdateTime < 0) { + blockingUpdateTime = now(); + blockingEventTime = resolveEventTimeStamp(); + blockingEventType = resolveEventType(); + } + } else if (isTransitionLane(lane)) { + if (transitionUpdateTime < 0) { + transitionUpdateTime = now(); + if (transitionStartTime < 0) { + transitionEventTime = resolveEventTimeStamp(); + transitionEventType = resolveEventType(); + } + } + } +} + +export function clearBlockingTimers(): void { + blockingUpdateTime = -1.1; +} + +export function startAsyncTransitionTimer(): void { + if (!enableProfilerTimer || !enableComponentPerformanceTrack) { + return; + } + if (transitionStartTime < 0 && transitionUpdateTime < 0) { + transitionStartTime = now(); + transitionEventTime = resolveEventTimeStamp(); + transitionEventType = resolveEventType(); + } +} + +export function hasScheduledTransitionWork(): boolean { + // If we have setState on a transition or scheduled useActionState update. + return transitionUpdateTime > -1; +} + +// We use this marker to indicate that we have scheduled a render to be performed +// but it's not an explicit state update. +const ACTION_STATE_MARKER = -0.5; + +export function startActionStateUpdate(): void { + if (!enableProfilerTimer || !enableComponentPerformanceTrack) { + return; + } + if (transitionUpdateTime < 0) { + transitionUpdateTime = ACTION_STATE_MARKER; + } +} + +export function clearAsyncTransitionTimer(): void { + transitionStartTime = -1.1; +} + +export function clearTransitionTimers(): void { + transitionStartTime = -1.1; + transitionUpdateTime = -1.1; +} + +export function clampBlockingTimers(finalTime: number): void { + if (!enableProfilerTimer || !enableComponentPerformanceTrack) { + return; + } + // If we had new updates come in while we were still rendering or committing, we don't want + // those update times to create overlapping tracks in the performance timeline so we clamp + // them to the end of the commit phase. + if (blockingUpdateTime >= 0 && blockingUpdateTime < finalTime) { + blockingUpdateTime = finalTime; + } + if (blockingEventTime >= 0 && blockingEventTime < finalTime) { + blockingEventTime = finalTime; + } +} + +export function clampTransitionTimers(finalTime: number): void { + if (!enableProfilerTimer || !enableComponentPerformanceTrack) { + return; + } + // If we had new updates come in while we were still rendering or committing, we don't want + // those update times to create overlapping tracks in the performance timeline so we clamp + // them to the end of the commit phase. + if (transitionStartTime >= 0 && transitionStartTime < finalTime) { + transitionStartTime = finalTime; + } + if (transitionUpdateTime >= 0 && transitionUpdateTime < finalTime) { + transitionUpdateTime = finalTime; + } + if (transitionEventTime >= 0 && transitionEventTime < finalTime) { + transitionEventTime = finalTime; + } +} + export function pushNestedEffectDurations(): number { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return 0; @@ -136,6 +248,13 @@ export function syncNestedUpdateFlag(): void { } } +export function recordRenderTime(): void { + if (!enableProfilerTimer || !enableComponentPerformanceTrack) { + return; + } + renderStartTime = now(); +} + export function recordCompleteTime(): void { if (!enableProfilerTimer) { return; diff --git a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js index 753c2d849b19a..60726514474fb 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js @@ -83,6 +83,12 @@ describe('ReactFiberHostContext', () => { } return DefaultEventPriority; }, + resolveEventType: function () { + return null; + }, + resolveEventTimeStamp: function () { + return -1.1; + }, shouldAttemptEagerTransition() { return false; }, diff --git a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js index 0826f9d95ee0d..1f525d9a05c52 100644 --- a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js @@ -73,6 +73,8 @@ export const getInstanceFromScope = $$$config.getInstanceFromScope; export const setCurrentUpdatePriority = $$$config.setCurrentUpdatePriority; export const getCurrentUpdatePriority = $$$config.getCurrentUpdatePriority; export const resolveUpdatePriority = $$$config.resolveUpdatePriority; +export const resolveEventType = $$$config.resolveEventType; +export const resolveEventTimeStamp = $$$config.resolveEventTimeStamp; export const shouldAttemptEagerTransition = $$$config.shouldAttemptEagerTransition; export const detachDeletedInstance = $$$config.detachDeletedInstance; diff --git a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js index 9d62e8a19ccf2..cb38a985eb800 100644 --- a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js +++ b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js @@ -224,6 +224,13 @@ export function resolveUpdatePriority(): EventPriority { } return DefaultEventPriority; } +export function resolveEventType(): null | string { + return null; +} + +export function resolveEventTimeStamp(): number { + return -1.1; +} export function shouldAttemptEagerTransition(): boolean { return false; } diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 0d7aead65f81d..14aacca63a7ca 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -178,6 +178,9 @@ describe(`onRender`, () => { 'read current time', 'read current time', 'read current time', + 'read current time', + 'read current time', + 'read current time', ]); } else { assertLog([ @@ -212,6 +215,9 @@ describe(`onRender`, () => { 'read current time', 'read current time', 'read current time', + 'read current time', + 'read current time', + 'read current time', ]); } else { assertLog([ From 5d19e1c8d1a6c0b5cd7532d43b707191eaf105b7 Mon Sep 17 00:00:00 2001 From: Edmond Chui <1967998+EdmondChuiHW@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:25:44 +0100 Subject: [PATCH 182/426] Fix: profiling crashes #30661 #28838 (#31024) ## Summary Profiling fails sometimes because `onProfilingStatus` is called repeatedly on some occasions, e.g. multiple calls to `getProfilingStatus`. Subsequent calls should be a no-op if the profiling status hasn't changed. Reported via #30661 #28838. > [!TIP] > Hide whitespace changes on this PR screenshot showing the UI controls for hiding
whitespace changes on GitHub ## How did you test this change? Tested as part of Fusebox implementation of reload-to-profile. https://github.com/facebook/react/pull/31021?#discussion_r1770589753 --- .../src/devtools/ProfilerStore.js | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/ProfilerStore.js b/packages/react-devtools-shared/src/devtools/ProfilerStore.js index 46b2edcab4d32..a55487ec19a37 100644 --- a/packages/react-devtools-shared/src/devtools/ProfilerStore.js +++ b/packages/react-devtools-shared/src/devtools/ProfilerStore.js @@ -289,6 +289,10 @@ export default class ProfilerStore extends EventEmitter<{ }; onProfilingStatus: (isProfiling: boolean) => void = isProfiling => { + if (this._isProfiling === isProfiling) { + return; + } + if (isProfiling) { this._dataBackends.splice(0); this._dataFrontend = null; @@ -315,36 +319,34 @@ export default class ProfilerStore extends EventEmitter<{ }); } - if (this._isProfiling !== isProfiling) { - this._isProfiling = isProfiling; + this._isProfiling = isProfiling; - // Invalidate suspense cache if profiling data is being (re-)recorded. - // Note that we clear again, in case any views read from the cache while profiling. - // (That would have resolved a now-stale value without any profiling data.) - this._cache.invalidate(); + // Invalidate suspense cache if profiling data is being (re-)recorded. + // Note that we clear again, in case any views read from the cache while profiling. + // (That would have resolved a now-stale value without any profiling data.) + this._cache.invalidate(); - this.emit('isProfiling'); + this.emit('isProfiling'); - // If we've just finished a profiling session, we need to fetch data stored in each renderer interface - // and re-assemble it on the front-end into a format (ProfilingDataFrontend) that can power the Profiler UI. - // During this time, DevTools UI should probably not be interactive. - if (!isProfiling) { - this._dataBackends.splice(0); - this._rendererQueue.clear(); + // If we've just finished a profiling session, we need to fetch data stored in each renderer interface + // and re-assemble it on the front-end into a format (ProfilingDataFrontend) that can power the Profiler UI. + // During this time, DevTools UI should probably not be interactive. + if (!isProfiling) { + this._dataBackends.splice(0); + this._rendererQueue.clear(); - // Only request data from renderers that actually logged it. - // This avoids unnecessary bridge requests and also avoids edge case mixed renderer bugs. - // (e.g. when v15 and v16 are both present) - this._rendererIDsThatReportedProfilingData.forEach(rendererID => { - if (!this._rendererQueue.has(rendererID)) { - this._rendererQueue.add(rendererID); + // Only request data from renderers that actually logged it. + // This avoids unnecessary bridge requests and also avoids edge case mixed renderer bugs. + // (e.g. when v15 and v16 are both present) + this._rendererIDsThatReportedProfilingData.forEach(rendererID => { + if (!this._rendererQueue.has(rendererID)) { + this._rendererQueue.add(rendererID); - this._bridge.send('getProfilingData', {rendererID}); - } - }); + this._bridge.send('getProfilingData', {rendererID}); + } + }); - this.emit('isProcessingData'); - } + this.emit('isProcessingData'); } }; } From 4e9540e3c2a8f9ae56318b967939c99b3a815190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 23 Sep 2024 14:09:48 -0400 Subject: [PATCH 183/426] [Fiber] Log the Render/Commit phases and the gaps in between (#31016) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A slight behavior change here too is that I now mark the start of the commit phase before the BeforeMutationEffect phase. This affects `` too. The named sequences are as follows: Render -> Suspended or Throttled -> Commit -> Waiting for Paint -> Remaining Effects The Suspended phase is only logged if we delay the Commit due to CSS / images. The Throttled phase is only logged if we delay the commit due to the Suspense throttling timer. Screenshot 2024-09-20 at 9 14 23 PM I don't yet log render phases that don't complete. I think I also need to special case renders that or don't commit after being suspended. --- .../src/ReactFiberCommitEffects.js | 22 ++-- .../src/ReactFiberCommitWork.js | 12 +- .../src/ReactFiberPerformanceTrack.js | 65 ++++++++++ .../src/ReactFiberWorkLoop.js | 115 ++++++++++++++---- .../src/ReactProfilerTimer.js | 12 +- .../__tests__/ReactProfiler-test.internal.js | 2 + 6 files changed, 184 insertions(+), 44 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitEffects.js b/packages/react-reconciler/src/ReactFiberCommitEffects.js index 8b1d4ceb6f9bb..4d10c9ee6faff 100644 --- a/packages/react-reconciler/src/ReactFiberCommitEffects.js +++ b/packages/react-reconciler/src/ReactFiberCommitEffects.js @@ -899,7 +899,7 @@ function safelyCallDestroy( function commitProfiler( finishedWork: Fiber, current: Fiber | null, - commitTime: number, + commitStartTime: number, effectDuration: number, ) { const {id, onCommit, onRender} = finishedWork.memoizedProps; @@ -918,7 +918,7 @@ function commitProfiler( finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, - commitTime, + commitStartTime, ); } @@ -928,7 +928,7 @@ function commitProfiler( finishedWork.memoizedProps.id, phase, effectDuration, - commitTime, + commitStartTime, ); } } @@ -937,7 +937,7 @@ function commitProfiler( export function commitProfilerUpdate( finishedWork: Fiber, current: Fiber | null, - commitTime: number, + commitStartTime: number, effectDuration: number, ) { if (enableProfilerTimer) { @@ -948,11 +948,11 @@ export function commitProfilerUpdate( commitProfiler, finishedWork, current, - commitTime, + commitStartTime, effectDuration, ); } else { - commitProfiler(finishedWork, current, commitTime, effectDuration); + commitProfiler(finishedWork, current, commitStartTime, effectDuration); } } catch (error) { captureCommitPhaseError(finishedWork, finishedWork.return, error); @@ -963,7 +963,7 @@ export function commitProfilerUpdate( function commitProfilerPostCommitImpl( finishedWork: Fiber, current: Fiber | null, - commitTime: number, + commitStartTime: number, passiveEffectDuration: number, ): void { const {id, onPostCommit} = finishedWork.memoizedProps; @@ -976,14 +976,14 @@ function commitProfilerPostCommitImpl( } if (typeof onPostCommit === 'function') { - onPostCommit(id, phase, passiveEffectDuration, commitTime); + onPostCommit(id, phase, passiveEffectDuration, commitStartTime); } } export function commitProfilerPostCommit( finishedWork: Fiber, current: Fiber | null, - commitTime: number, + commitStartTime: number, passiveEffectDuration: number, ) { try { @@ -993,14 +993,14 @@ export function commitProfilerPostCommit( commitProfilerPostCommitImpl, finishedWork, current, - commitTime, + commitStartTime, passiveEffectDuration, ); } else { commitProfilerPostCommitImpl( finishedWork, current, - commitTime, + commitStartTime, passiveEffectDuration, ); } diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 5965dbe8db0a8..89aa35d760b26 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -99,8 +99,7 @@ import { Cloned, } from './ReactFiberFlags'; import { - commitTime, - completeTime, + commitStartTime, pushNestedEffectDurations, popNestedEffectDurations, bubbleNestedEffectDurations, @@ -505,7 +504,7 @@ function commitLayoutEffectOnFiber( commitProfilerUpdate( finishedWork, current, - commitTime, + commitStartTime, profilerInstance.effectDuration, ); } else { @@ -2345,7 +2344,7 @@ export function reappearLayoutEffects( commitProfilerUpdate( finishedWork, current, - commitTime, + commitStartTime, profilerInstance.effectDuration, ); } else { @@ -2568,6 +2567,7 @@ export function commitPassiveMountEffects( finishedWork: Fiber, committedLanes: Lanes, committedTransitions: Array | null, + renderEndTime: number, // Profiling-only ): void { resetComponentEffectTimers(); @@ -2576,7 +2576,7 @@ export function commitPassiveMountEffects( finishedWork, committedLanes, committedTransitions, - enableProfilerTimer && enableComponentPerformanceTrack ? completeTime : 0, + enableProfilerTimer && enableComponentPerformanceTrack ? renderEndTime : 0, ); } @@ -2763,7 +2763,7 @@ function commitPassiveMountOnFiber( finishedWork.alternate, // This value will still reflect the previous commit phase. // It does not get reset until the start of the next commit phase. - commitTime, + commitStartTime, profilerInstance.passiveEffectDuration, ); } else { diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 94a7ec458fc57..3d52dcf4e1073 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -164,3 +164,68 @@ export function logTransitionStart( } } } + +export function logRenderPhase(startTime: number, endTime: number): void { + if (supportsUserTiming) { + reusableComponentDevToolDetails.color = 'primary-dark'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure('Render', reusableComponentOptions); + } +} + +export function logSuspenseThrottlePhase( + startTime: number, + endTime: number, +): void { + // This was inside a throttled Suspense boundary commit. + if (supportsUserTiming) { + reusableComponentDevToolDetails.color = 'secondary-light'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure('Throttled', reusableComponentOptions); + } +} + +export function logSuspendedCommitPhase( + startTime: number, + endTime: number, +): void { + // This means the commit was suspended on CSS or images. + if (supportsUserTiming) { + reusableComponentDevToolDetails.color = 'secondary-light'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure('Suspended', reusableComponentOptions); + } +} + +export function logCommitPhase(startTime: number, endTime: number): void { + if (supportsUserTiming) { + reusableComponentDevToolDetails.color = 'secondary-dark'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure('Commit', reusableComponentOptions); + } +} + +export function logPaintYieldPhase(startTime: number, endTime: number): void { + if (supportsUserTiming) { + reusableComponentDevToolDetails.color = 'secondary-light'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure('Waiting for Paint', reusableComponentOptions); + } +} + +export function logPassiveCommitPhase( + startTime: number, + endTime: number, +): void { + if (supportsUserTiming) { + reusableComponentDevToolDetails.color = 'secondary-dark'; + reusableComponentOptions.start = startTime; + reusableComponentOptions.end = endTime; + performance.measure('Remaining Effects', reusableComponentOptions); + } +} diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index b576309dc84ab..c13b9c65a65a4 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -71,6 +71,12 @@ import { import { logBlockingStart, logTransitionStart, + logRenderPhase, + logSuspenseThrottlePhase, + logSuspendedCommitPhase, + logCommitPhase, + logPaintYieldPhase, + logPassiveCommitPhase, } from './ReactFiberPerformanceTrack'; import { @@ -239,9 +245,11 @@ import { clampTransitionTimers, markNestedUpdateScheduled, renderStartTime, + commitStartTime, + commitEndTime, recordRenderTime, - recordCompleteTime, recordCommitTime, + recordCommitEndTime, resetNestedUpdateFlag, startProfilerTimer, stopProfilerTimerIfRunningAndRecordDuration, @@ -601,6 +609,7 @@ let rootDoesHavePassiveEffects: boolean = false; let rootWithPendingPassiveEffects: FiberRoot | null = null; let pendingPassiveEffectsLanes: Lanes = NoLanes; let pendingPassiveEffectsRemainingLanes: Lanes = NoLanes; +let pendingPassiveEffectsRenderEndTime: number = -0; // Profiling-only let pendingPassiveTransitions: Array | null = null; // Use these to prevent an infinite loop of nested updates @@ -1119,10 +1128,11 @@ function finishConcurrentRender( finishedWork: Fiber, lanes: Lanes, ) { + let renderEndTime = 0; if (enableProfilerTimer && enableComponentPerformanceTrack) { // Track when we finished the last unit of work, before we actually commit it. // The commit can be suspended/blocked until we commit it. - recordCompleteTime(); + renderEndTime = now(); } // TODO: The fact that most of these branches are identical suggests that some @@ -1182,6 +1192,9 @@ function finishConcurrentRender( workInProgressDeferredLane, workInProgressRootInterleavedUpdatedLanes, workInProgressSuspendedRetryLanes, + IMMEDIATE_COMMIT, + renderStartTime, + renderEndTime, ); } else { if ( @@ -1227,6 +1240,9 @@ function finishConcurrentRender( workInProgressRootInterleavedUpdatedLanes, workInProgressSuspendedRetryLanes, workInProgressRootDidSkipSuspendedSiblings, + THROTTLED_COMMIT, + renderStartTime, + renderEndTime, ), msUntilTimeout, ); @@ -1244,6 +1260,9 @@ function finishConcurrentRender( workInProgressRootInterleavedUpdatedLanes, workInProgressSuspendedRetryLanes, workInProgressRootDidSkipSuspendedSiblings, + IMMEDIATE_COMMIT, + renderStartTime, + renderEndTime, ); } } @@ -1259,6 +1278,9 @@ function commitRootWhenReady( updatedLanes: Lanes, suspendedRetryLanes: Lanes, didSkipSuspendedSiblings: boolean, + suspendedCommitReason: SuspendedCommitReason, // Profiling-only + completedRenderStartTime: number, // Profiling-only + completedRenderEndTime: number, // Profiling-only ) { // TODO: Combine retry throttling with Suspensey commits. Right now they run // one after the other. @@ -1299,6 +1321,7 @@ function commitRootWhenReady( spawnedLane, updatedLanes, suspendedRetryLanes, + SUSPENDED_COMMIT, ), ); markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings); @@ -1315,6 +1338,9 @@ function commitRootWhenReady( spawnedLane, updatedLanes, suspendedRetryLanes, + suspendedCommitReason, + completedRenderStartTime, + completedRenderEndTime, ); } @@ -1506,8 +1532,9 @@ export function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes): null { return null; } + let renderEndTime = 0; if (enableProfilerTimer && enableComponentPerformanceTrack) { - recordCompleteTime(); + renderEndTime = now(); } // We now have a consistent tree. Because this is a sync render, we @@ -1523,6 +1550,9 @@ export function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes): null { workInProgressDeferredLane, workInProgressRootInterleavedUpdatedLanes, workInProgressSuspendedRetryLanes, + IMMEDIATE_COMMIT, + renderStartTime, + renderEndTime, ); // Before exiting, make sure there's a callback scheduled for the next @@ -3016,6 +3046,11 @@ function unwindUnitOfWork(unitOfWork: Fiber, skipSiblings: boolean): void { workInProgress = null; } +type SuspendedCommitReason = 0 | 1 | 2; +const IMMEDIATE_COMMIT = 0; +const SUSPENDED_COMMIT = 1; +const THROTTLED_COMMIT = 2; + function commitRoot( root: FiberRoot, recoverableErrors: null | Array>, @@ -3024,6 +3059,9 @@ function commitRoot( spawnedLane: Lane, updatedLanes: Lanes, suspendedRetryLanes: Lanes, + suspendedCommitReason: SuspendedCommitReason, // Profiling-only + completedRenderStartTime: number, // Profiling-only + completedRenderEndTime: number, // Profiling-only ) { // TODO: This no longer makes any sense. We already wrap the mutation and // layout phases. Should be able to remove. @@ -3041,6 +3079,9 @@ function commitRoot( spawnedLane, updatedLanes, suspendedRetryLanes, + suspendedCommitReason, + completedRenderStartTime, + completedRenderEndTime, ); } finally { ReactSharedInternals.T = prevTransition; @@ -3059,6 +3100,9 @@ function commitRootImpl( spawnedLane: Lane, updatedLanes: Lanes, suspendedRetryLanes: Lanes, + suspendedCommitReason: SuspendedCommitReason, // Profiling-only + completedRenderStartTime: number, // Profiling-only + completedRenderEndTime: number, // Profiling-only ) { do { // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which @@ -3078,6 +3122,12 @@ function commitRootImpl( const finishedWork = root.finishedWork; const lanes = root.finishedLanes; + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // Log the previous render phase once we commit. I.e. we weren't interrupted. + setCurrentTrackFromLanes(lanes); + logRenderPhase(completedRenderStartTime, completedRenderEndTime); + } + if (__DEV__) { if (enableDebugTracing) { logCommitStarted(lanes); @@ -3174,6 +3224,7 @@ function commitRootImpl( if (!rootDoesHavePassiveEffects) { rootDoesHavePassiveEffects = true; pendingPassiveEffectsRemainingLanes = remainingLanes; + pendingPassiveEffectsRenderEndTime = completedRenderEndTime; // workInProgressTransitions might be overwritten, so we want // to store it in pendingPassiveTransitions until they get processed // We need to pass this through as an argument to commitRoot @@ -3182,7 +3233,7 @@ function commitRootImpl( // with setTimeout pendingPassiveTransitions = transitions; scheduleCallback(NormalSchedulerPriority, () => { - flushPassiveEffects(); + flushPassiveEffects(true); // This render triggered passive effects: release the root cache pool // *after* passive effects fire to avoid freeing a cache pool that may // be referenced by a node in the tree (HostRoot, Cache boundary etc) @@ -3191,6 +3242,19 @@ function commitRootImpl( } } + if (enableProfilerTimer) { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); + if (enableComponentPerformanceTrack) { + if (suspendedCommitReason === SUSPENDED_COMMIT) { + logSuspendedCommitPhase(completedRenderEndTime, commitStartTime); + } else if (suspendedCommitReason === THROTTLED_COMMIT) { + logSuspenseThrottlePhase(completedRenderEndTime, commitStartTime); + } + } + } + // Check if there are any effects in the whole tree. // TODO: This is left over from the effect list implementation, where we had // to check for the existence of `firstEffect` to satisfy Flow. I think the @@ -3226,12 +3290,6 @@ function commitRootImpl( finishedWork, ); - if (enableProfilerTimer) { - // Mark the current commit time to be shared by all Profilers in this - // batch. This enables them to be grouped later. - recordCommitTime(); - } - // The next phase is the mutation phase, where we mutate the host tree. commitMutationEffects(root, finishedWork, lanes); @@ -3282,12 +3340,11 @@ function commitRootImpl( } else { // No effects. root.current = finishedWork; - // Measure these anyway so the flamegraph explicitly shows that there were - // no effects. - // TODO: Maybe there's a better way to report this. - if (enableProfilerTimer) { - recordCommitTime(); - } + } + + if (enableProfilerTimer && enableComponentPerformanceTrack) { + recordCommitEndTime(); + logCommitPhase(commitStartTime, commitEndTime); } const rootDidHavePassiveEffects = rootDoesHavePassiveEffects; @@ -3504,7 +3561,7 @@ function releaseRootPooledCache(root: FiberRoot, remainingLanes: Lanes) { } } -export function flushPassiveEffects(): boolean { +export function flushPassiveEffects(wasDelayedCommit?: boolean): boolean { // Returns whether passive effects were flushed. // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should // probably just combine the two functions. I believe they were only separate @@ -3529,7 +3586,7 @@ export function flushPassiveEffects(): boolean { try { setCurrentUpdatePriority(priority); ReactSharedInternals.T = null; - return flushPassiveEffectsImpl(); + return flushPassiveEffectsImpl(wasDelayedCommit); } finally { setCurrentUpdatePriority(previousPriority); ReactSharedInternals.T = prevTransition; @@ -3543,7 +3600,7 @@ export function flushPassiveEffects(): boolean { return false; } -function flushPassiveEffectsImpl() { +function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) { if (rootWithPendingPassiveEffects === null) { return false; } @@ -3579,6 +3636,12 @@ function flushPassiveEffectsImpl() { } } + let passiveEffectStartTime = 0; + if (enableProfilerTimer && enableComponentPerformanceTrack) { + passiveEffectStartTime = now(); + logPaintYieldPhase(commitEndTime, passiveEffectStartTime); + } + if (enableSchedulingProfiler) { markPassiveEffectsStarted(lanes); } @@ -3587,7 +3650,13 @@ function flushPassiveEffectsImpl() { executionContext |= CommitContext; commitPassiveUnmountEffects(root.current); - commitPassiveMountEffects(root, root.current, lanes, transitions); + commitPassiveMountEffects( + root, + root.current, + lanes, + transitions, + pendingPassiveEffectsRenderEndTime, + ); if (__DEV__) { if (enableDebugTracing) { @@ -3606,7 +3675,11 @@ function flushPassiveEffectsImpl() { executionContext = prevExecutionContext; if (enableProfilerTimer && enableComponentPerformanceTrack) { - finalizeRender(lanes, now()); + const passiveEffectsEndTime = now(); + if (wasDelayedCommit) { + logPassiveCommitPhase(passiveEffectStartTime, passiveEffectsEndTime); + } + finalizeRender(lanes, passiveEffectsEndTime); } flushSyncWorkOnAllRoots(); diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index cf3133524813e..0df3427fe86b2 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -28,8 +28,8 @@ import * as Scheduler from 'scheduler'; const {unstable_now: now} = Scheduler; export let renderStartTime: number = -0; -export let completeTime: number = -0; -export let commitTime: number = -0; +export let commitStartTime: number = -0; +export let commitEndTime: number = -0; export let profilerStartTime: number = -1.1; export let profilerEffectDuration: number = -0; export let componentEffectDuration: number = -0; @@ -255,18 +255,18 @@ export function recordRenderTime(): void { renderStartTime = now(); } -export function recordCompleteTime(): void { +export function recordCommitTime(): void { if (!enableProfilerTimer) { return; } - completeTime = now(); + commitStartTime = now(); } -export function recordCommitTime(): void { +export function recordCommitEndTime(): void { if (!enableProfilerTimer) { return; } - commitTime = now(); + commitEndTime = now(); } export function startProfilerTimer(fiber: Fiber): void { diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 14aacca63a7ca..522c3a11cf29d 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -181,6 +181,7 @@ describe(`onRender`, () => { 'read current time', 'read current time', 'read current time', + 'read current time', ]); } else { assertLog([ @@ -218,6 +219,7 @@ describe(`onRender`, () => { 'read current time', 'read current time', 'read current time', + 'read current time', ]); } else { assertLog([ From 79bcf6eb23cd781bedbfccfe8d1507d18fd2c623 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 23 Sep 2024 14:58:05 -0400 Subject: [PATCH 184/426] Fix missing trailing / in commit artifacts workflow The trailing / was being omitted, so instead of moving the cjs directory itself, it would move only its contents instead. This broke some internal path assumptions. Additionally, updates the step to create the react-dom directory prior to moving. ghstack-source-id: b6eedb0c88cd3aa3a786a3d3d280ede5ee81a063 Pull Request resolved: https://github.com/facebook/react/pull/31026 --- .github/workflows/runtime_commit_artifacts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 2baabaf59f5c5..30906cc3ea930 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -118,14 +118,14 @@ jobs: run: | BASE_FOLDER='compiled-rn/facebook-fbsource/xplat/js' mkdir -p ${BASE_FOLDER}/react-native-github/Libraries/Renderer/ - mkdir -p ${BASE_FOLDER}/RKJSModules/vendor/react/{scheduler,react,react-is,react-test-renderer}/ + mkdir -p ${BASE_FOLDER}/RKJSModules/vendor/react/{scheduler,react,react-dom,react-is,react-test-renderer}/ # Move React Native renderer mv build/react-native/implementations/ $BASE_FOLDER/react-native-github/Libraries/Renderer/ mv build/react-native/shims/ $BASE_FOLDER/react-native-github/Libraries/Renderer/ mv build/facebook-react-native/scheduler/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/scheduler/ mv build/facebook-react-native/react/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react/ - mv build/facebook-react-native/react-dom/cjs $BASE_FOLDER/RKJSModules/vendor/react/react-dom/ + mv build/facebook-react-native/react-dom/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-dom/ mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/ mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/ From 5b19dc0f06e92d3ed0aa93be3c5bbe2298da5df6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 23 Sep 2024 15:31:10 -0400 Subject: [PATCH 185/426] Allow forcing a build in artifacts workflow dispatch Sometimes it is useful to bypass the revision check when we need to make changes to the runtime_commit_artifacts script. The `force` input can be passed via the GitHub UI for manual runs of the workflow. ghstack-source-id: cf9e32c01a565d86980277115f41e3e116adf376 Pull Request resolved: https://github.com/facebook/react/pull/31027 --- .../workflows/runtime_commit_artifacts.yml | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 30906cc3ea930..ac312531ac6fa 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -11,6 +11,11 @@ on: commit_sha: required: false type: string + force: + description: 'Force a commit to the builds/... branches' + required: true + default: false + type: boolean env: TZ: /usr/share/zoneinfo/America/Los_Angeles @@ -196,6 +201,7 @@ jobs: grep -rl "$CURRENT_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$CURRENT_VERSION_MODERN/$LAST_VERSION_MODERN/g" grep -rl "$CURRENT_VERSION_MODERN" ./compiled || echo "Modern version reverted" - name: Check for changes + if: !inputs.force id: check_should_commit run: | echo "Full git status" @@ -213,7 +219,7 @@ jobs: echo "should_commit=false" >> "$GITHUB_OUTPUT" fi - name: Re-apply version changes - if: steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != '' + if: inputs.force || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != '') env: CURRENT_VERSION_CLASSIC: ${{ needs.download_artifacts.outputs.current_version_classic }} CURRENT_VERSION_MODERN: ${{ needs.download_artifacts.outputs.current_version_modern }} @@ -230,12 +236,12 @@ jobs: grep -rl "$LAST_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$LAST_VERSION_MODERN/$CURRENT_VERSION_MODERN/g" grep -rl "$LAST_VERSION_MODERN" ./compiled || echo "Classic version re-applied" - name: Will commit these changes - if: steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' run: | echo ":" git status -u - name: Commit changes to branch - if: steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: | @@ -272,6 +278,7 @@ jobs: grep -rl "$CURRENT_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$CURRENT_VERSION/$LAST_VERSION/g" grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "Version reverted" - name: Check for changes + if: !inputs.force id: check_should_commit run: | echo "Full git status" @@ -290,7 +297,7 @@ jobs: echo "should_commit=false" >> "$GITHUB_OUTPUT" fi - name: Re-apply version changes - if: steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_rn != '' + if: inputs.force || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_rn != '') env: CURRENT_VERSION: ${{ needs.download_artifacts.outputs.current_version_rn }} LAST_VERSION: ${{ needs.download_artifacts.outputs.last_version_rn }} @@ -300,12 +307,12 @@ jobs: grep -rl "$LAST_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$LAST_VERSION/$CURRENT_VERSION/g" grep -rl "$LAST_VERSION" ./compiled-rn || echo "Version re-applied" - name: Add files for signing - if: steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' run: | echo ":" git add . - name: Signing files - if: steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' uses: actions/github-script@v7 with: script: | @@ -388,12 +395,12 @@ jobs: console.error('Error signing files:', e); } - name: Will commit these changes - if: steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' run: | git add . git status - name: Commit changes to branch - if: steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: | From 4708fb92c24bbc769acbc075de6105590fd29edc Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 23 Sep 2024 17:36:53 -0400 Subject: [PATCH 186/426] Fix runtime_commit_artifacts workflow I messed up the yml syntax and also realized that our script doesn't currently handle renames or deletes, so I fixed that ghstack-source-id: 7d481a951abaabd1a2985c8959d8acb7103ed12e Pull Request resolved: https://github.com/facebook/react/pull/31028 --- .../workflows/runtime_commit_artifacts.yml | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index ac312531ac6fa..9710fa4eed9ff 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -171,7 +171,7 @@ jobs: commit_www_artifacts: needs: download_artifacts - if: ${{ (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.www_branch_count == '0') || github.ref == 'refs/heads/meta-www' }} + if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.www_branch_count == '0') runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -201,7 +201,7 @@ jobs: grep -rl "$CURRENT_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$CURRENT_VERSION_MODERN/$LAST_VERSION_MODERN/g" grep -rl "$CURRENT_VERSION_MODERN" ./compiled || echo "Modern version reverted" - name: Check for changes - if: !inputs.force + if: inputs.force != true id: check_should_commit run: | echo "Full git status" @@ -219,7 +219,7 @@ jobs: echo "should_commit=false" >> "$GITHUB_OUTPUT" fi - name: Re-apply version changes - if: inputs.force || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != '') + if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_classic != '' && needs.download_artifacts.outputs.last_version_modern != '') env: CURRENT_VERSION_CLASSIC: ${{ needs.download_artifacts.outputs.current_version_classic }} CURRENT_VERSION_MODERN: ${{ needs.download_artifacts.outputs.current_version_modern }} @@ -236,12 +236,12 @@ jobs: grep -rl "$LAST_VERSION_MODERN" ./compiled | xargs -r sed -i -e "s/$LAST_VERSION_MODERN/$CURRENT_VERSION_MODERN/g" grep -rl "$LAST_VERSION_MODERN" ./compiled || echo "Classic version re-applied" - name: Will commit these changes - if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' run: | echo ":" git status -u - name: Commit changes to branch - if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: | @@ -255,7 +255,7 @@ jobs: commit_fbsource_artifacts: needs: download_artifacts - if: ${{ (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.fbsource_branch_count == '0') || github.ref == 'refs/heads/meta-fbsource' }} + if: inputs.force == true || (github.ref == 'refs/heads/main' && needs.download_artifacts.outputs.fbsource_branch_count == '0') runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -278,7 +278,7 @@ jobs: grep -rl "$CURRENT_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$CURRENT_VERSION/$LAST_VERSION/g" grep -rl "$CURRENT_VERSION" ./compiled-rn || echo "Version reverted" - name: Check for changes - if: !inputs.force + if: inputs.force != 'true' id: check_should_commit run: | echo "Full git status" @@ -297,7 +297,7 @@ jobs: echo "should_commit=false" >> "$GITHUB_OUTPUT" fi - name: Re-apply version changes - if: inputs.force || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_rn != '') + if: inputs.force == true || (steps.check_should_commit.outputs.should_commit == 'true' && needs.download_artifacts.outputs.last_version_rn != '') env: CURRENT_VERSION: ${{ needs.download_artifacts.outputs.current_version_rn }} LAST_VERSION: ${{ needs.download_artifacts.outputs.last_version_rn }} @@ -307,12 +307,12 @@ jobs: grep -rl "$LAST_VERSION" ./compiled-rn | xargs -r sed -i -e "s/$LAST_VERSION/$CURRENT_VERSION/g" grep -rl "$LAST_VERSION" ./compiled-rn || echo "Version re-applied" - name: Add files for signing - if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' run: | echo ":" git add . - name: Signing files - if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' uses: actions/github-script@v7 with: script: | @@ -366,8 +366,9 @@ jobs: console.log('Signing files in directory:', directory); try { const result = execSync(`git status --porcelain ${directory}`, {encoding: 'utf8'}); + console.log(result); - // Parse the git status output to get file paths + // Parse the git status output to get file paths! const files = result.split('\n').filter(file => file.endsWith('.js')); if (files.length === 0) { @@ -376,7 +377,14 @@ jobs: ); } else { files.forEach(line => { - const file = line.slice(3).trim(); + let file = null; + if (line.startsWith('D ')) { + return; + } else if (line.startsWith('R ')) { + file = line.slice(line.indexOf('->') + 3); + } else { + file = line.slice(3).trim(); + } if (file) { console.log(' Signing file:', file); const originalContents = fs.readFileSync(file, 'utf8'); @@ -395,12 +403,12 @@ jobs: console.error('Error signing files:', e); } - name: Will commit these changes - if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' run: | git add . git status - name: Commit changes to branch - if: inputs.force || steps.check_should_commit.outputs.should_commit == 'true' + if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: | From 04bd67a4906d387ecdb8cbc798144dec2db811a5 Mon Sep 17 00:00:00 2001 From: Hendrik Liebau Date: Tue, 24 Sep 2024 08:34:53 +0200 Subject: [PATCH 187/426] Resolve references to deduped owner objects (#30549) This is a follow-up from #30528 to not only handle props (the critical change), but also the owner ~and stack~ of a referenced element. ~Handling stacks here is rather academic because the Flight Server currently does not deduplicate owner stacks. And if they are really identical, we should probably just dedupe the whole element.~ EDIT: Removed from the PR. Handling owner objects on the other hand is an actual requirement as reported in https://github.com/vercel/next.js/issues/69545. This problem only affects the stable release channel, as the absence of owner stacks allows for the specific kind of shared owner deduping as demonstrated in the unit test. --- .../react-client/src/ReactFlightClient.js | 27 +++-- .../__tests__/ReactFlightDOMBrowser-test.js | 113 ++++++++++++++++++ .../react-server/src/ReactFlightServer.js | 3 + 3 files changed, 134 insertions(+), 9 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 597536c961333..83c509dab46a8 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -937,26 +937,35 @@ function waitForReference( } value = value[path[i]]; } - parentObject[key] = map(response, value); + const mappedValue = map(response, value); + parentObject[key] = mappedValue; // If this is the root object for a model reference, where `handler.value` // is a stale `null`, the resolved value can be used directly. if (key === '' && handler.value === null) { - handler.value = parentObject[key]; + handler.value = mappedValue; } - // If the parent object is an unparsed React element tuple and its outlined - // props have now been resolved, we also need to update the props of the - // parsed element object (i.e. handler.value). + // If the parent object is an unparsed React element tuple, we also need to + // update the props and owner of the parsed element object (i.e. + // handler.value). if ( parentObject[0] === REACT_ELEMENT_TYPE && - key === '3' && typeof handler.value === 'object' && handler.value !== null && - handler.value.$$typeof === REACT_ELEMENT_TYPE && - handler.value.props === null + handler.value.$$typeof === REACT_ELEMENT_TYPE ) { - handler.value.props = parentObject[key]; + const element: any = handler.value; + switch (key) { + case '3': + element.props = mappedValue; + break; + case '4': + if (__DEV__) { + element._owner = mappedValue; + } + break; + } } handler.deps--; diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index fa1e65862564e..0408a63fc512f 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -630,6 +630,119 @@ describe('ReactFlightDOMBrowser', () => { expect(container.innerHTML).toBe('
'); }); + it('should handle references to deduped owner objects', async () => { + // This is replicating React components as generated by @svgr/webpack: + let path1a: React.ReactNode; + let path1b: React.ReactNode; + let path2: React.ReactNode; + + function Svg1() { + return ReactServer.createElement( + 'svg', + {id: '1'}, + path1a || (path1a = ReactServer.createElement('path', {})), + path1b || (path1b = ReactServer.createElement('path', {})), + ); + } + + function Svg2() { + return ReactServer.createElement( + 'svg', + {id: '2'}, + path2 || (path2 = ReactServer.createElement('path', {})), + ); + } + + function Server() { + return ReactServer.createElement( + ReactServer.Fragment, + {}, + ReactServer.createElement(Svg1), + ReactServer.createElement(Svg2), + ); + } + + let stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(, webpackMap), + ); + + function ClientRoot({response}) { + return use(response); + } + + let response = ReactServerDOMClient.createFromReadableStream(stream); + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + + await act(() => { + root.render(); + }); + + const expectedHtml = + ''; + + expect(container.innerHTML).toBe(expectedHtml); + + // Render a second time: + + // Assigning the path elements to variables in module scope (here simulated + // with the test's function scope), and rendering a second time, prevents + // the owner of the path elements (i.e. Svg1/Svg2) to be deduped. The owner + // of the path in Svg1 is fully inlined. The owner of the owner of the path + // in Svg2 is Server, which is deduped and replaced with a reference to the + // owner of the owner of the path in Svg1. This nested owner is actually + // Server from the previous render pass, which is kinda broken and libraries + // probably shouldn't generate code like this. This reference can only be + // resolved properly if owners are specifically handled when resolving + // outlined models. + + stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream(, webpackMap), + ); + + response = ReactServerDOMClient.createFromReadableStream(stream); + + await act(() => { + root.render(); + }); + + expect(container.innerHTML).toBe(expectedHtml); + + if (__DEV__) { + const resolvedPath1b = await response.value[0].props.children[1]._payload; + + expect(resolvedPath1b._owner).toEqual( + expect.objectContaining({ + name: 'Svg1', + env: 'Server', + key: null, + owner: expect.objectContaining({ + name: 'Server', + env: 'Server', + key: null, + owner: null, + }), + }), + ); + + const resolvedPath2 = response.value[1].props.children; + + expect(resolvedPath2._owner).toEqual( + expect.objectContaining({ + name: 'Svg2', + env: 'Server', + key: null, + owner: expect.objectContaining({ + name: 'Server', + env: 'Server', + key: null, + owner: null, + }), + }), + ); + } + }); + it('should progressively reveal server components', async () => { let reportedErrors = []; diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index f0e632c5499b0..5d79482de0186 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -2665,6 +2665,9 @@ function renderModelDestructive( case '3': propertyName = 'props'; break; + case '4': + propertyName = '_owner'; + break; } } writtenObjects.set(value, parentReference + ':' + propertyName); From fc4a33eaa9c935ac860ab6043b95d55540068571 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 24 Sep 2024 17:49:19 +0100 Subject: [PATCH 188/426] fix: consider alternate as a key for componentLogsEntry when inspecting raw fiber instance (#31009) Related - https://github.com/facebook/react/pull/30899. Looks like this was missed. We actually do this when we record errors and warnings before sending them via Bridge: https://github.com/facebook/react/blob/e4953922a99b5477c3bcf98cdaa2b13ac0a81f0d/packages/react-devtools-shared/src/backend/fiber/renderer.js#L2169-L2173 So, what is happening in the end, errors or warnings are displayed in the Tree, but when user clicks on the component, nothing is shown, because `fiberToComponentLogsMap` has only `alternate` as a key. --- .../react-devtools-shared/src/backend/fiber/renderer.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index b8636c557ea25..d93e713911561 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -1029,6 +1029,10 @@ export function attach( if (devtoolsInstance.kind === FIBER_INSTANCE) { const fiber = devtoolsInstance.data; componentLogsEntry = fiberToComponentLogsMap.get(fiber); + + if (componentLogsEntry === undefined && fiber.alternate !== null) { + componentLogsEntry = fiberToComponentLogsMap.get(fiber.alternate); + } } else { const componentInfo = devtoolsInstance.data; componentLogsEntry = componentInfoToComponentLogsMap.get(componentInfo); @@ -4248,7 +4252,10 @@ export function attach( source = getSourceForFiberInstance(fiberInstance); } - const componentLogsEntry = fiberToComponentLogsMap.get(fiber); + let componentLogsEntry = fiberToComponentLogsMap.get(fiber); + if (componentLogsEntry === undefined && fiber.alternate !== null) { + componentLogsEntry = fiberToComponentLogsMap.get(fiber.alternate); + } return { id: fiberInstance.id, From a15bbe14751287cb7ac124ff88f694d0883f3ac6 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 24 Sep 2024 19:51:21 +0100 Subject: [PATCH 189/426] refactor: data source for errors and warnings tracking is now in Store (#31010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stacked on https://github.com/facebook/react/pull/31009. 1. Instead of keeping `showInlineWarningsAndErrors` in `Settings` context (which was removed in https://github.com/facebook/react/pull/30610), `Store` will now have a boolean flag, which controls if the UI should be displaying information about errors and warnings. 2. The errors and warnings counters in the Tree view are now counting only unique errors. This makes more sense, because it is part of the Elements Tree view, so ideally it should be showing number of components with errors and number of components of warnings. Consider this example: 2.1. Warning for element `A` was emitted once and warning for element `B` was emitted twice. 2.2. With previous implementation, we would show `3 ⚠️`, because in total there were 3 warnings in total. If user tries to iterate through these, it will only take 2 steps to do the full cycle, because there are only 2 elements with warnings (with one having same warning, which was emitted twice). 2.3 With current implementation, we would show `2 ⚠️`. Inspecting the element with doubled warning will still show the warning counter (2) before the warning message. With these changes, the feature correctly works. https://fburl.com/a7fw92m4 --- .../src/__tests__/store-test.js | 4 +- .../__tests__/storeComponentFilters-test.js | 16 ++--- .../src/devtools/store.js | 68 ++++++++++++++---- .../src/devtools/views/Components/Element.js | 6 +- .../InspectedElementErrorsAndWarningsTree.js | 8 +-- .../src/devtools/views/Components/Tree.js | 72 +++++++++---------- .../views/Settings/DebuggingSettings.js | 4 ++ .../views/Settings/SettingsContext.js | 14 +--- 8 files changed, 109 insertions(+), 83 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/store-test.js b/packages/react-devtools-shared/src/__tests__/store-test.js index 92e7fc6586111..93c7048b2bc5b 100644 --- a/packages/react-devtools-shared/src/__tests__/store-test.js +++ b/packages/react-devtools-shared/src/__tests__/store-test.js @@ -2148,8 +2148,8 @@ describe('Store', () => { act(() => render()); }); expect(store).toMatchInlineSnapshot(`[root]`); - expect(store.errorCount).toBe(0); - expect(store.warningCount).toBe(0); + expect(store.componentWithErrorCount).toBe(0); + expect(store.componentWithWarningCount).toBe(0); }); // Regression test for https://github.com/facebook/react/issues/23202 diff --git a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js index 432fb1771b6ff..26cd51383297f 100644 --- a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js +++ b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js @@ -420,8 +420,8 @@ describe('Store component filters', () => { }); expect(store).toMatchInlineSnapshot(``); - expect(store.errorCount).toBe(0); - expect(store.warningCount).toBe(0); + expect(store.componentWithErrorCount).toBe(0); + expect(store.componentWithWarningCount).toBe(0); await actAsync(async () => (store.componentFilters = [])); expect(store).toMatchInlineSnapshot(` @@ -460,8 +460,8 @@ describe('Store component filters', () => { ]), ); expect(store).toMatchInlineSnapshot(`[root]`); - expect(store.errorCount).toBe(0); - expect(store.warningCount).toBe(0); + expect(store.componentWithErrorCount).toBe(0); + expect(store.componentWithWarningCount).toBe(0); await actAsync(async () => (store.componentFilters = [])); expect(store).toMatchInlineSnapshot(` @@ -510,8 +510,8 @@ describe('Store component filters', () => { }); expect(store).toMatchInlineSnapshot(``); - expect(store.errorCount).toBe(0); - expect(store.warningCount).toBe(0); + expect(store.componentWithErrorCount).toBe(0); + expect(store.componentWithWarningCount).toBe(0); await actAsync(async () => (store.componentFilters = [])); expect(store).toMatchInlineSnapshot(` @@ -550,8 +550,8 @@ describe('Store component filters', () => { ]), ); expect(store).toMatchInlineSnapshot(`[root]`); - expect(store.errorCount).toBe(0); - expect(store.warningCount).toBe(0); + expect(store.componentWithErrorCount).toBe(0); + expect(store.componentWithWarningCount).toBe(0); await actAsync(async () => (store.componentFilters = [])); expect(store).toMatchInlineSnapshot(` diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js index b54907338b372..b1544126d8d6e 100644 --- a/packages/react-devtools-shared/src/devtools/store.js +++ b/packages/react-devtools-shared/src/devtools/store.js @@ -114,8 +114,8 @@ export default class Store extends EventEmitter<{ _bridge: FrontendBridge; // Computed whenever _errorsAndWarnings Map changes. - _cachedErrorCount: number = 0; - _cachedWarningCount: number = 0; + _cachedComponentWithErrorCount: number = 0; + _cachedComponentWithWarningCount: number = 0; _cachedErrorAndWarningTuples: ErrorAndWarningTuples | null = null; // Should new nodes be collapsed by default when added to the tree? @@ -196,6 +196,7 @@ export default class Store extends EventEmitter<{ _shouldCheckBridgeProtocolCompatibility: boolean = false; _hookSettings: $ReadOnly | null = null; + _shouldShowWarningsAndErrors: boolean = false; constructor(bridge: FrontendBridge, config?: Config) { super(); @@ -383,8 +384,24 @@ export default class Store extends EventEmitter<{ return this._bridgeProtocol; } - get errorCount(): number { - return this._cachedErrorCount; + get componentWithErrorCount(): number { + if (!this._shouldShowWarningsAndErrors) { + return 0; + } + + return this._cachedComponentWithErrorCount; + } + + get componentWithWarningCount(): number { + if (!this._shouldShowWarningsAndErrors) { + return 0; + } + + return this._cachedComponentWithWarningCount; + } + + get displayingErrorsAndWarningsEnabled(): boolean { + return this._shouldShowWarningsAndErrors; } get hasOwnerMetadata(): boolean { @@ -480,10 +497,6 @@ export default class Store extends EventEmitter<{ return this._unsupportedRendererVersionDetected; } - get warningCount(): number { - return this._cachedWarningCount; - } - containsElement(id: number): boolean { return this._idToElement.has(id); } @@ -581,7 +594,11 @@ export default class Store extends EventEmitter<{ } // Returns a tuple of [id, index] - getElementsWithErrorsAndWarnings(): Array<{id: number, index: number}> { + getElementsWithErrorsAndWarnings(): ErrorAndWarningTuples { + if (!this._shouldShowWarningsAndErrors) { + return []; + } + if (this._cachedErrorAndWarningTuples !== null) { return this._cachedErrorAndWarningTuples; } @@ -615,6 +632,10 @@ export default class Store extends EventEmitter<{ errorCount: number, warningCount: number, } { + if (!this._shouldShowWarningsAndErrors) { + return {errorCount: 0, warningCount: 0}; + } + return this._errorsAndWarnings.get(id) || {errorCount: 0, warningCount: 0}; } @@ -1325,16 +1346,21 @@ export default class Store extends EventEmitter<{ this._cachedErrorAndWarningTuples = null; if (haveErrorsOrWarningsChanged) { - let errorCount = 0; - let warningCount = 0; + let componentWithErrorCount = 0; + let componentWithWarningCount = 0; this._errorsAndWarnings.forEach(entry => { - errorCount += entry.errorCount; - warningCount += entry.warningCount; + if (entry.errorCount > 0) { + componentWithErrorCount++; + } + + if (entry.warningCount > 0) { + componentWithWarningCount++; + } }); - this._cachedErrorCount = errorCount; - this._cachedWarningCount = warningCount; + this._cachedComponentWithErrorCount = componentWithErrorCount; + this._cachedComponentWithWarningCount = componentWithWarningCount; } if (haveRootsChanged) { @@ -1528,9 +1554,21 @@ export default class Store extends EventEmitter<{ onHookSettings: (settings: $ReadOnly) => void = settings => { this._hookSettings = settings; + + this.setShouldShowWarningsAndErrors(settings.showInlineWarningsAndErrors); this.emit('hookSettings', settings); }; + setShouldShowWarningsAndErrors(status: boolean): void { + const previousStatus = this._shouldShowWarningsAndErrors; + this._shouldShowWarningsAndErrors = status; + + if (previousStatus !== status) { + // Propagate to subscribers, although tree state has not changed + this.emit('mutated', [[], new Map()]); + } + } + // The Store should never throw an Error without also emitting an event. // Otherwise Store errors will be invisible to users, // but the downstream errors they cause will be reported as bugs. diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Element.js b/packages/react-devtools-shared/src/devtools/views/Components/Element.js index f5c30d2d2b0d6..48bfbe90906ff 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Element.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Element.js @@ -12,7 +12,6 @@ import {Fragment, useContext, useMemo, useState} from 'react'; import Store from 'react-devtools-shared/src/devtools/store'; import ButtonIcon from '../ButtonIcon'; import {TreeDispatcherContext, TreeStateContext} from './TreeContext'; -import {SettingsContext} from '../Settings/SettingsContext'; import {StoreContext} from '../context'; import {useSubscription} from '../hooks'; import {logEvent} from 'react-devtools-shared/src/Logger'; @@ -37,7 +36,6 @@ export default function Element({data, index, style}: Props): React.Node { const {ownerFlatTree, ownerID, selectedElementID} = useContext(TreeStateContext); const dispatch = useContext(TreeDispatcherContext); - const {showInlineWarningsAndErrors} = React.useContext(SettingsContext); const element = ownerFlatTree !== null @@ -181,7 +179,7 @@ export default function Element({data, index, style}: Props): React.Node { className={styles.BadgesBlock} /> - {showInlineWarningsAndErrors && errorCount > 0 && ( + {errorCount > 0 && ( )} - {showInlineWarningsAndErrors && warningCount > 0 && ( + {warningCount > 0 && ( diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Tree.js b/packages/react-devtools-shared/src/devtools/views/Components/Tree.js index 136baa1205de2..db1bf9a98c135 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Tree.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Tree.js @@ -73,7 +73,7 @@ export default function Tree(props: Props): React.Node { const [treeFocused, setTreeFocused] = useState(false); - const {lineHeight, showInlineWarningsAndErrors} = useContext(SettingsContext); + const {lineHeight} = useContext(SettingsContext); // Make sure a newly selected element is visible in the list. // This is helpful for things like the owners list and search. @@ -325,8 +325,8 @@ export default function Tree(props: Props): React.Node { const errorsOrWarningsSubscription = useMemo( () => ({ getCurrentValue: () => ({ - errors: store.errorCount, - warnings: store.warningCount, + errors: store.componentWithErrorCount, + warnings: store.componentWithWarningCount, }), subscribe: (callback: Function) => { store.addListener('mutated', callback); @@ -370,40 +370,38 @@ export default function Tree(props: Props): React.Node { }> {ownerID !== null ? : } - {showInlineWarningsAndErrors && - ownerID === null && - (errors > 0 || warnings > 0) && ( - -
, + { + onError(x) { + errors.push(x.message); + }, + onAllReady() { + isCompleteCalls++; + }, }, - }, - ); - pipe(writable); - - jest.runAllTimers(); + ); + pipeable.pipe(writable); + abort = pipeable.abort; + }); expect(output.result).toContain('Loading'); expect(isCompleteCalls).toBe(0); @@ -360,26 +369,28 @@ describe('ReactDOMFizzServerNode', () => { let isCompleteCalls = 0; const errors = []; const {writable, output, completed} = getTestWritable(); - const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream( -
- - }> - + let abort; + await act(() => { + const pipeable = ReactDOMFizzServer.renderToPipeableStream( +
+ + }> + + - -
, - { - onError(x) { - errors.push(x.message); - }, - onAllReady() { - isCompleteCalls++; +
, + { + onError(x) { + errors.push(x.message); + }, + onAllReady() { + isCompleteCalls++; + }, }, - }, - ); - pipe(writable); - - jest.runAllTimers(); + ); + pipeable.pipe(writable); + abort = pipeable.abort; + }); expect(output.result).toContain('Loading'); expect(isCompleteCalls).toBe(0); @@ -428,15 +439,15 @@ describe('ReactDOMFizzServerNode', () => { const client = new DelayClient(); const {writable, output, completed} = getTestWritable(); - ReactDOMFizzServer.renderToPipeableStream( - - - - - , - ).pipe(writable); - - jest.runAllTimers(); + await act(() => { + ReactDOMFizzServer.renderToPipeableStream( + + + + + , + ).pipe(writable); + }); expect(output.error).toBe(undefined); expect(output.result).toContain('loading'); @@ -481,29 +492,28 @@ describe('ReactDOMFizzServerNode', () => { output: output0, completed: completed0, } = getTestWritable(); - ReactDOMFizzServer.renderToPipeableStream( - - - - - , - ).pipe(writable0); - const client1 = new DelayClient(); const { writable: writable1, output: output1, completed: completed1, } = getTestWritable(); - ReactDOMFizzServer.renderToPipeableStream( - - - - - , - ).pipe(writable1); - - jest.runAllTimers(); + await act(() => { + ReactDOMFizzServer.renderToPipeableStream( + + + + + , + ).pipe(writable0); + ReactDOMFizzServer.renderToPipeableStream( + + + + + , + ).pipe(writable1); + }); expect(output0.error).toBe(undefined); expect(output0.result).toContain('loading'); @@ -552,22 +562,22 @@ describe('ReactDOMFizzServerNode', () => { const client = new DelayClient(); const {writable, output, completed} = getTestWritable(); - ReactDOMFizzServer.renderToPipeableStream( - <> - - - - - - - - - - - , - ).pipe(writable); - - jest.runAllTimers(); + await act(() => { + ReactDOMFizzServer.renderToPipeableStream( + <> + + + + + + + + + + + , + ).pipe(writable); + }); expect(output.error).toBe(undefined); expect(output.result).toContain('loading'); @@ -630,13 +640,14 @@ describe('ReactDOMFizzServerNode', () => { expect(isComplete).toBe(true); }); - it('should encode multibyte characters correctly without nulls (#24985)', () => { + it('should encode multibyte characters correctly without nulls (#24985)', async () => { const {writable, output} = getTestWritable(); - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( -
{Array(700).fill('ののの')}
, - ); - pipe(writable); - jest.runAllTimers(); + await act(() => { + const {pipe} = ReactDOMFizzServer.renderToPipeableStream( +
{Array(700).fill('ののの')}
, + ); + pipe(writable); + }); expect(output.result.indexOf('\u0000')).toBe(-1); expect(output.result).toEqual( '
' + Array(700).fill('ののの').join('') + '
', diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index 0f863d24b9c57..f384908720a33 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -316,10 +316,11 @@ type Segment = { textEmbedded: boolean, }; -const OPEN = 0; -const ABORTING = 1; -const CLOSING = 2; -const CLOSED = 3; +const OPENING = 10; +const OPEN = 11; +const ABORTING = 12; +const CLOSING = 13; +const CLOSED = 14; export opaque type Request = { destination: null | Destination, @@ -328,7 +329,7 @@ export opaque type Request = { +renderState: RenderState, +rootFormatContext: FormatContext, +progressiveChunkSize: number, - status: 0 | 1 | 2 | 3, + status: 10 | 11 | 12 | 13 | 14, fatalError: mixed, nextSegmentId: number, allPendingTasks: number, // when it reaches zero, we can close the connection. @@ -424,7 +425,7 @@ function RequestInstance( progressiveChunkSize === undefined ? DEFAULT_PROGRESSIVE_CHUNK_SIZE : progressiveChunkSize; - this.status = OPEN; + this.status = OPENING; this.fatalError = null; this.nextSegmentId = 0; this.allPendingTasks = 0; @@ -688,7 +689,7 @@ function pingTask(request: Request, task: Task): void { pingedTasks.push(task); if (request.pingedTasks.length === 1) { request.flushScheduled = request.destination !== null; - if (request.trackedPostpones !== null) { + if (request.trackedPostpones !== null || request.status === OPENING) { scheduleMicrotask(() => performWork(request)); } else { scheduleWork(() => performWork(request)); @@ -4977,43 +4978,38 @@ function flushCompletedQueues( export function startWork(request: Request): void { request.flushScheduled = request.destination !== null; - if (request.trackedPostpones !== null) { - // When prerendering we use microtasks for pinging work - if (supportsRequestStorage) { - scheduleMicrotask(() => - requestStorage.run(request, performWork, request), - ); - } else { - scheduleMicrotask(() => performWork(request)); - } + // When prerendering we use microtasks for pinging work + if (supportsRequestStorage) { + scheduleMicrotask(() => requestStorage.run(request, performWork, request)); } else { - // When rendering/resuming we use regular tasks and we also emit early preloads - if (supportsRequestStorage) { - scheduleWork(() => requestStorage.run(request, performWork, request)); - } else { - scheduleWork(() => performWork(request)); + scheduleMicrotask(() => performWork(request)); + } + scheduleWork(() => { + if (request.status === OPENING) { + request.status = OPEN; } - // this is either a regular render or a resume. For regular render we want - // to call emitEarlyPreloads after the first performWork because we want - // are responding to a live request and need to balance sending something early - // (i.e. don't want for the shell to finish) but we need something to send. - // The only implementation of this is for DOM at the moment and during resumes nothing - // actually emits but the code paths here are the same. - // During a prerender we don't want to be too aggressive in emitting early preloads - // because we aren't responding to a live request and we can wait for the prerender to - // postpone before we emit anything. - if (supportsRequestStorage) { - scheduleWork(() => + + if (request.trackedPostpones === null) { + // this is either a regular render or a resume. For regular render we want + // to call emitEarlyPreloads after the first performWork because we want + // are responding to a live request and need to balance sending something early + // (i.e. don't want for the shell to finish) but we need something to send. + // The only implementation of this is for DOM at the moment and during resumes nothing + // actually emits but the code paths here are the same. + // During a prerender we don't want to be too aggressive in emitting early preloads + // because we aren't responding to a live request and we can wait for the prerender to + // postpone before we emit anything. + if (supportsRequestStorage) { requestStorage.run( request, enqueueEarlyPreloadsAfterInitialWork, request, - ), - ); - } else { - scheduleWork(() => enqueueEarlyPreloadsAfterInitialWork(request)); + ); + } else { + enqueueEarlyPreloadsAfterInitialWork(request); + } } - } + }); } function enqueueEarlyPreloadsAfterInitialWork(request: Request) { @@ -5095,7 +5091,7 @@ export function stopFlowing(request: Request): void { // This is called to early terminate a request. It puts all pending boundaries in client rendered state. export function abort(request: Request, reason: mixed): void { - if (request.status === OPEN) { + if (request.status === OPEN || request.status === OPENING) { request.status = ABORTING; } From d34da5cdb9266ba7928f78107c87383ae211f0f9 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 17:28:01 -0400 Subject: [PATCH 212/426] [ci] Fix incorrect sha / commit messages in manual Meta builds ghstack-source-id: 0790b32d293f7b528e458cb4b8718d8c2c422dab Pull Request resolved: https://github.com/facebook/react/pull/31083 --- .github/workflows/runtime_commit_artifacts.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 6ff1bdb5a638d..b8b21eb288d40 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -82,7 +82,7 @@ jobs: working-directory: scripts/release - name: Download artifacts for base revision run: | - GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.sha }} + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha || github.sha }} - name: Display structure of build run: ls -R build - name: Strip @license from eslint plugin and react-refresh @@ -245,9 +245,9 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: | - ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} + ${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }} - DiffTrain build for [${{ github.sha }}](https://github.com/facebook/react/commit/${{ github.sha }}) + DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }}) branch: builds/facebook-www commit_user_name: ${{ github.triggering_actor }} commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }} @@ -412,9 +412,9 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: | - ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} + ${{ github.event.workflow_run.head_commit.message || format('Manual build of {0}', github.event.workflow_run.head_sha || github.sha) }} - DiffTrain build for [${{ github.sha }}](https://github.com/facebook/react/commit/${{ github.sha }}) + DiffTrain build for [${{ github.event.workflow_run.head_sha || github.sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha || github.sha }}) branch: builds/facebook-fbsource commit_user_name: ${{ github.triggering_actor }} commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }} From 3edc000d7717027a1ce23611070a56358040a554 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 17:34:28 -0400 Subject: [PATCH 213/426] [compiler] Fix broken tests ghstack-source-id: 000a37ae1f819eef676dcd52410d5231cd2d50fe Pull Request resolved: https://github.com/facebook/react/pull/31078 --- ...-namespace-assigned-to-temporary.expect.md | 38 ++++++++++--------- ...epro-cx-namespace-assigned-to-temporary.js | 18 +++++---- ...e-outer-scope-within-value-block.expect.md | 6 ++- .../mutate-outer-scope-within-value-block.ts | 2 + .../useCallback-dep-scope-pruned.expect.md | 6 ++- .../useCallback-dep-scope-pruned.ts | 2 + ...g-ternary-test-instruction-scope.expect.md | 6 ++- ...locating-ternary-test-instruction-scope.ts | 2 + .../allow-locals-named-like-hooks.expect.md | 6 +-- .../allow-locals-named-like-hooks.js | 2 +- 10 files changed, 56 insertions(+), 32 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.expect.md index 82afa9c51de94..aeae54128b03a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.expect.md @@ -19,15 +19,17 @@ function Component() { ); } -function cx(obj) { - const classes = []; - for (const [key, value] of Object.entries(obj)) { - if (value) { - classes.push(key); +const cx = { + foo(obj) { + const classes = []; + for (const [key, value] of Object.entries(obj)) { + if (value) { + classes.push(key); + } } - } - return classes.join(' '); -} + return classes.join(' '); + }, +}; function useTheme() { return { @@ -71,15 +73,17 @@ function Component() { return t1; } -function cx(obj) { - const classes = []; - for (const [key, value] of Object.entries(obj)) { - if (value) { - classes.push(key); +const cx = { + foo(obj) { + const classes = []; + for (const [key, value] of Object.entries(obj)) { + if (value) { + classes.push(key); + } } - } - return classes.join(" "); -} + return classes.join(" "); + }, +}; function useTheme() { return { @@ -97,4 +101,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: exception) cx.foo is not a function \ No newline at end of file +(kind: ok)
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.js index c0eb2f2dcd01c..fe7abb7cdf6ac 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/meta-isms/repro-cx-namespace-assigned-to-temporary.js @@ -15,15 +15,17 @@ function Component() { ); } -function cx(obj) { - const classes = []; - for (const [key, value] of Object.entries(obj)) { - if (value) { - classes.push(key); +const cx = { + foo(obj) { + const classes = []; + for (const [key, value] of Object.entries(obj)) { + if (value) { + classes.push(key); + } } - } - return classes.join(' '); -} + return classes.join(' '); + }, +}; function useTheme() { return { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.expect.md index 7649bfd1fa574..dcade9000aa8e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.expect.md @@ -4,6 +4,8 @@ ```javascript import {CONST_TRUE, identity, shallowCopy} from 'shared-runtime'; +function mutate(_: unknown) {} + /** * There are three values with their own scopes in this fixture. * - arr, whose mutable range extends to the `mutate(...)` call @@ -45,6 +47,8 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; import { CONST_TRUE, identity, shallowCopy } from "shared-runtime"; +function mutate(_) {} + /** * There are three values with their own scopes in this fixture. * - arr, whose mutable range extends to the `mutate(...)` call @@ -91,4 +95,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: exception) mutate is not defined \ No newline at end of file +(kind: ok) \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.ts index 72a5fa2e1b3bb..fd4452bebbd86 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/mutate-outer-scope-within-value-block.ts @@ -1,5 +1,7 @@ import {CONST_TRUE, identity, shallowCopy} from 'shared-runtime'; +function mutate(_: unknown) {} + /** * There are three values with their own scopes in this fixture. * - arr, whose mutable range extends to the `mutate(...)` call diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.expect.md index 184779869e9a3..687d9565ba88c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.expect.md @@ -6,6 +6,8 @@ import {useCallback} from 'react'; import {identity, useIdentity} from 'shared-runtime'; +function mutate(_: unknown) {} + /** * Repro showing a manual memo whose declaration (useCallback's 1st argument) * is memoized, but not its dependency (x). In this case, `x`'s scope is pruned @@ -33,6 +35,8 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe import { useCallback } from "react"; import { identity, useIdentity } from "shared-runtime"; +function mutate(_) {} + /** * Repro showing a manual memo whose declaration (useCallback's 1st argument) * is memoized, but not its dependency (x). In this case, `x`'s scope is pruned @@ -62,4 +66,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: exception) mutate is not defined \ No newline at end of file +(kind: ok) "[[ function params=0 ]]" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.ts index 8fdd74ea571a2..23de8c2c259a9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-dep-scope-pruned.ts @@ -2,6 +2,8 @@ import {useCallback} from 'react'; import {identity, useIdentity} from 'shared-runtime'; +function mutate(_: unknown) {} + /** * Repro showing a manual memo whose declaration (useCallback's 1st argument) * is memoized, but not its dependency (x). In this case, `x`'s scope is pruned diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.expect.md index cd31d1fb0bb8a..01161d0941e5f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.expect.md @@ -4,6 +4,8 @@ ```javascript import {identity, makeObject_Primitives} from 'shared-runtime'; +function useHook() {} + function useTest({cond}) { const val = makeObject_Primitives(); @@ -31,6 +33,8 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; import { identity, makeObject_Primitives } from "shared-runtime"; +function useHook() {} + function useTest(t0) { const $ = _c(3); const { cond } = t0; @@ -64,4 +68,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: exception) useHook is not defined \ No newline at end of file +(kind: ok) {"a":0,"b":"value1","c":true} \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.ts index e1c62a3cf1384..017ea326b406a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-allocating-ternary-test-instruction-scope.ts @@ -1,5 +1,7 @@ import {identity, makeObject_Primitives} from 'shared-runtime'; +function useHook() {} + function useTest({cond}) { const val = makeObject_Primitives(); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.expect.md index 59563ea67fa8f..002bc6ee89bef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -import {makeObject_Primitives} from 'shared-runtime'; +import {makeObject_Primitives, Stringify} from 'shared-runtime'; function Component(props) { let useFeature = makeObject_Primitives(); @@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; -import { makeObject_Primitives } from "shared-runtime"; +import { makeObject_Primitives, Stringify } from "shared-runtime"; function Component(props) { const $ = _c(2); @@ -75,4 +75,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: exception) Stringify is not defined \ No newline at end of file +(kind: ok)
{"val":{"a":0,"b":"value1","c":true},"children":[2,"[[ cyclic ref *1 ]]",null]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.js index 246abee218802..8715db07ece6d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rules-of-hooks/allow-locals-named-like-hooks.js @@ -1,4 +1,4 @@ -import {makeObject_Primitives} from 'shared-runtime'; +import {makeObject_Primitives, Stringify} from 'shared-runtime'; function Component(props) { let useFeature = makeObject_Primitives(); From db240980a3aeae65f148b1edf5a1187a2331307e Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 27 Sep 2024 15:15:15 -0400 Subject: [PATCH 214/426] [playground] Decouple playground from compiler Currently the playground is setup as a linked workspace for the compiler which complicates our yarn workspace setup and means that snap can sometimes pull in a different version of react than was otherwise specified. There's no real reason to have these workspaces combined so let's split them up. ghstack-source-id: 56ab064b2fc45366f5d96d37c5d4c5dc26590234 Pull Request resolved: https://github.com/facebook/react/pull/31081 --- .github/workflows/compiler_playground.yml | 12 +- compiler/apps/playground/app/layout.tsx | 6 +- compiler/apps/playground/app/page.tsx | 2 +- .../components/Editor/EditorImpl.tsx | 20 +- .../playground/components/Editor/Input.tsx | 59 +- .../playground/components/Editor/Output.tsx | 27 +- .../playground/components/Editor/index.tsx | 6 +- .../apps/playground/components/Header.tsx | 20 +- compiler/apps/playground/components/Logo.tsx | 2 +- .../playground/components/StoreContext.tsx | 2 +- compiler/apps/playground/lib/createContext.ts | 7 +- .../lib/reactCompilerMonacoDiagnostics.ts | 4 +- compiler/apps/playground/lib/stores/store.ts | 8 +- compiler/apps/playground/package.json | 43 +- compiler/apps/playground/playwright.config.js | 3 +- .../apps/playground/scripts/link-compiler.sh | 15 + compiler/apps/playground/tsconfig.json | 3 +- compiler/apps/playground/yarn.lock | 3653 +++++++++++++++++ compiler/package.json | 12 +- .../babel-plugin-react-compiler/package.json | 6 +- compiler/packages/snap/package.json | 3 +- compiler/yarn.lock | 2881 ++----------- 22 files changed, 4142 insertions(+), 2652 deletions(-) create mode 100755 compiler/apps/playground/scripts/link-compiler.sh create mode 100644 compiler/apps/playground/yarn.lock diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index a96950ccc0b2a..d7a6306ee4318 100644 --- a/.github/workflows/compiler_playground.yml +++ b/.github/workflows/compiler_playground.yml @@ -15,7 +15,7 @@ env: defaults: run: - working-directory: compiler + working-directory: compiler/apps/playground jobs: playground: @@ -27,13 +27,17 @@ jobs: with: node-version-file: '.nvmrc' cache: yarn - cache-dependency-path: compiler/yarn.lock + cache-dependency-path: compiler/**/yarn.lock - name: Restore cached node_modules uses: actions/cache@v4 id: node_modules with: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('compiler/**/yarn.lock') }} - - run: yarn install --frozen-lockfile + - name: yarn install compiler + run: yarn install --frozen-lockfile + working-directory: compiler + - name: yarn install playground + run: yarn install --frozen-lockfile - run: npx playwright install --with-deps chromium - - run: yarn workspace playground test + - run: yarn test diff --git a/compiler/apps/playground/app/layout.tsx b/compiler/apps/playground/app/layout.tsx index 3e888ae955a89..9a6daac239faf 100644 --- a/compiler/apps/playground/app/layout.tsx +++ b/compiler/apps/playground/app/layout.tsx @@ -7,7 +7,11 @@ import '../styles/globals.css'; -export default function RootLayout({children}: {children: React.ReactNode}) { +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}): JSX.Element { 'use no memo'; return ( diff --git a/compiler/apps/playground/app/page.tsx b/compiler/apps/playground/app/page.tsx index 4b0da58a7028b..d5214af422e03 100644 --- a/compiler/apps/playground/app/page.tsx +++ b/compiler/apps/playground/app/page.tsx @@ -11,7 +11,7 @@ import {SnackbarProvider} from 'notistack'; import {Editor, Header, StoreProvider} from '../components'; import MessageSnackbar from '../components/Message'; -export default function Hoot() { +export default function Page(): JSX.Element { return ( (); + const results = new Map>(); const error = new CompilerError(); - const upsert = (result: PrintedCompilerPipelineValue) => { + const upsert: (result: PrintedCompilerPipelineValue) => void = result => { const entry = results.get(result.name); if (Array.isArray(entry)) { entry.push(result); @@ -273,13 +273,17 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { } } } catch (err) { - // error might be an invariant violation or other runtime error - // (i.e. object shape that is not CompilerError) + /** + * error might be an invariant violation or other runtime error + * (i.e. object shape that is not CompilerError) + */ if (err instanceof CompilerError && err.details.length > 0) { error.details.push(...err.details); } else { - // Handle unexpected failures by logging (to get a stack trace) - // and reporting + /** + * Handle unexpected failures by logging (to get a stack trace) + * and reporting + */ console.error(err); error.details.push( new CompilerErrorDetail({ @@ -297,7 +301,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { return [{kind: 'ok', results}, language]; } -export default function Editor() { +export default function Editor(): JSX.Element { const store = useStore(); const deferredStore = useDeferredValue(store); const dispatchStore = useStoreDispatch(); diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index c2ce8efc70d3f..34df68787db79 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -15,18 +15,17 @@ import {useEffect, useState} from 'react'; import {renderReactCompilerMarkers} from '../../lib/reactCompilerMonacoDiagnostics'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; -// TODO: Make TS recognize .d.ts files, in addition to loading them with webpack. -// @ts-ignore +// @ts-expect-error TODO: Make TS recognize .d.ts files, in addition to loading them with webpack. import React$Types from '../../node_modules/@types/react/index.d.ts'; loader.config({monaco}); type Props = { - errors: CompilerErrorDetail[]; + errors: Array; language: 'flow' | 'typescript'; }; -export default function Input({errors, language}: Props) { +export default function Input({errors, language}: Props): JSX.Element { const [monaco, setMonaco] = useState(null); const store = useStore(); const dispatchStore = useStoreDispatch(); @@ -38,18 +37,19 @@ export default function Input({errors, language}: Props) { const model = monaco.editor.getModel(uri); invariant(model, 'Model must exist for the selected input file.'); renderReactCompilerMarkers({monaco, model, details: errors}); - // N.B. that `tabSize` is a model property, not an editor property. - // So, the tab size has to be set per model. + /** + * N.B. that `tabSize` is a model property, not an editor property. + * So, the tab size has to be set per model. + */ model.updateOptions({tabSize: 2}); }, [monaco, errors]); - const flowDiagnosticDisable = [ - 7028 /* unused label */, 6133 /* var declared but not read */, - ]; useEffect(() => { - // Ignore "can only be used in TypeScript files." errors, since - // we want to support syntax highlighting for Flow (*.js) files - // and Flow is not a built-in language. + /** + * Ignore "can only be used in TypeScript files." errors, since + * we want to support syntax highlighting for Flow (*.js) files + * and Flow is not a built-in language. + */ if (!monaco) return; monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({ diagnosticCodesToIgnore: [ @@ -64,7 +64,9 @@ export default function Input({errors, language}: Props) { 8011, 8012, 8013, - ...(language === 'flow' ? flowDiagnosticDisable : []), + ...(language === 'flow' + ? [7028 /* unused label */, 6133 /* var declared but not read */] + : []), ], noSemanticValidation: true, // Monaco can't validate Flow component syntax @@ -72,7 +74,7 @@ export default function Input({errors, language}: Props) { }); }, [monaco, language]); - const handleChange = (value: string | undefined) => { + const handleChange: (value: string | undefined) => void = value => { if (!value) return; dispatchStore({ @@ -83,7 +85,10 @@ export default function Input({errors, language}: Props) { }); }; - const handleMount = (_: editor.IStandaloneCodeEditor, monaco: Monaco) => { + const handleMount: ( + _: editor.IStandaloneCodeEditor, + monaco: Monaco, + ) => void = (_, monaco) => { setMonaco(monaco); const tscOptions = { @@ -111,10 +116,12 @@ export default function Input({errors, language}: Props) { monaco.languages.typescript.javascriptDefaults.addExtraLib(...reactLib); monaco.languages.typescript.typescriptDefaults.addExtraLib(...reactLib); - // Remeasure the font in case the custom font is loaded only after - // Monaco Editor is mounted. - // N.B. that this applies also to the output editor as it seems - // Monaco Editor instances share the same font config. + /** + * Remeasure the font in case the custom font is loaded only after + * Monaco Editor is mounted. + * N.B. that this applies also to the output editor as it seems + * Monaco Editor instances share the same font config. + */ document.fonts.ready.then(() => { monaco.editor.remeasureFonts(); }); @@ -125,14 +132,18 @@ export default function Input({errors, language}: Props) { } + | {kind: 'ok'; results: Map>} | { kind: 'err'; - results: Map; + results: Map>; error: CompilerError; }; @@ -54,7 +54,10 @@ type Props = { compilerOutput: CompilerOutput; }; -async function tabify(source: string, compilerOutput: CompilerOutput) { +async function tabify( + source: string, + compilerOutput: CompilerOutput, +): Promise> { const tabs = new Map(); const reorderedTabs = new Map(); const concattedResults = new Map(); @@ -112,8 +115,10 @@ async function tabify(source: string, compilerOutput: CompilerOutput) { } // Ensure that JS and the JS source map come first if (topLevelFnDecls.length > 0) { - // Make a synthetic Program so we can have a single AST with all the top level - // FunctionDeclarations + /** + * Make a synthetic Program so we can have a single AST with all the top level + * FunctionDeclarations + */ const ast = t.program(topLevelFnDecls); const {code, sourceMapUrl} = await codegen(ast, source); reorderedTabs.set( @@ -175,7 +180,7 @@ function getSourceMapUrl(code: string, map: string): string | null { )}`; } -function Output({store, compilerOutput}: Props) { +function Output({store, compilerOutput}: Props): JSX.Element { const [tabsOpen, setTabsOpen] = useState>(() => new Set(['JS'])); const [tabs, setTabs] = useState>( () => new Map(), @@ -236,11 +241,13 @@ function TextTabContent({ output: string; diff: string | null; showInfoPanel: boolean; -}) { +}): JSX.Element { const [diffMode, setDiffMode] = useState(false); return ( - // Restrict MonacoEditor's height, since the config autoLayout:true - // will grow the editor to fit within parent element + /** + * Restrict MonacoEditor's height, since the config autoLayout:true + * will grow the editor to fit within parent element + */
{showInfoPanel ? (
diff --git a/compiler/apps/playground/components/Editor/index.tsx b/compiler/apps/playground/components/Editor/index.tsx index 62f0f4440758a..6fe7234d29c2a 100644 --- a/compiler/apps/playground/components/Editor/index.tsx +++ b/compiler/apps/playground/components/Editor/index.tsx @@ -7,8 +7,10 @@ import dynamic from 'next/dynamic'; -// monaco-editor is currently not compatible with ssr -// https://github.com/vercel/next.js/issues/31692 +/** + * monaco-editor is currently not compatible with ssr + * https://github.com/vercel/next.js/issues/31692 + */ const Editor = dynamic(() => import('./EditorImpl'), { ssr: false, }); diff --git a/compiler/apps/playground/components/Header.tsx b/compiler/apps/playground/components/Header.tsx index 76b20be7df4f7..cbaa6788eca9c 100644 --- a/compiler/apps/playground/components/Header.tsx +++ b/compiler/apps/playground/components/Header.tsx @@ -16,26 +16,26 @@ import {IconGitHub} from './Icons/IconGitHub'; import Logo from './Logo'; import {useStoreDispatch} from './StoreContext'; -export default function Header() { +export default function Header(): JSX.Element { const [showCheck, setShowCheck] = useState(false); const dispatchStore = useStoreDispatch(); const {enqueueSnackbar, closeSnackbar} = useSnackbar(); - const handleReset = () => { + const handleReset: () => void = () => { if (confirm('Are you sure you want to reset the playground?')) { - /* - Close open snackbars if any. This is necessary because when displaying - outputs (Preview or not), we only close previous snackbars if we received - new messages, which is needed in order to display "Bad URL" or success - messages when loading Playground for the first time. Otherwise, messages - such as "Bad URL" will be closed by the outputs calling `closeSnackbar`. - */ + /** + * Close open snackbars if any. This is necessary because when displaying + * outputs (Preview or not), we only close previous snackbars if we received + * new messages, which is needed in order to display "Bad URL" or success + * messages when loading Playground for the first time. Otherwise, messages + * such as "Bad URL" will be closed by the outputs calling `closeSnackbar`. + */ closeSnackbar(); dispatchStore({type: 'setStore', payload: {store: defaultStore}}); } }; - const handleShare = () => { + const handleShare: () => void = () => { navigator.clipboard.writeText(location.href).then(() => { enqueueSnackbar('URL copied to clipboard'); setShowCheck(true); diff --git a/compiler/apps/playground/components/Logo.tsx b/compiler/apps/playground/components/Logo.tsx index 06a623e5569cd..bac1573239be1 100644 --- a/compiler/apps/playground/components/Logo.tsx +++ b/compiler/apps/playground/components/Logo.tsx @@ -7,7 +7,7 @@ // https://github.com/reactjs/reactjs.org/blob/main/beta/src/components/Logo.tsx -export default function Logo(props: JSX.IntrinsicElements['svg']) { +export default function Logo(props: JSX.IntrinsicElements['svg']): JSX.Element { return ( () { +export default function createContext(): { + useContext: () => NonNullable; + Provider: React.Provider; +} { const context = React.createContext(null); - function useContext() { + function useContext(): NonNullable { const c = React.useContext(context); if (!c) throw new Error('useContext must be within a Provider with a value'); diff --git a/compiler/apps/playground/lib/reactCompilerMonacoDiagnostics.ts b/compiler/apps/playground/lib/reactCompilerMonacoDiagnostics.ts index 4352d643a50ac..76bcc5da37f55 100644 --- a/compiler/apps/playground/lib/reactCompilerMonacoDiagnostics.ts +++ b/compiler/apps/playground/lib/reactCompilerMonacoDiagnostics.ts @@ -46,9 +46,9 @@ function mapReactCompilerDiagnosticToMonacoMarker( type ReactCompilerMarkerConfig = { monaco: Monaco; model: editor.ITextModel; - details: CompilerErrorDetail[]; + details: Array; }; -let decorations: string[] = []; +let decorations: Array = []; export function renderReactCompilerMarkers({ monaco, model, diff --git a/compiler/apps/playground/lib/stores/store.ts b/compiler/apps/playground/lib/stores/store.ts index a916c1a0ada07..ad4a57cf914a9 100644 --- a/compiler/apps/playground/lib/stores/store.ts +++ b/compiler/apps/playground/lib/stores/store.ts @@ -28,7 +28,7 @@ export function decodeStore(hash: string): Store { /** * Serialize, encode, and save @param store to localStorage and update URL. */ -export function saveStore(store: Store) { +export function saveStore(store: Store): void { const hash = encodeStore(store); localStorage.setItem('playgroundStore', hash); history.replaceState({}, '', `#${hash}`); @@ -56,8 +56,10 @@ export function initStoreFromUrlOrLocalStorage(): Store { const encodedSourceFromLocal = localStorage.getItem('playgroundStore'); const encodedSource = encodedSourceFromUrl || encodedSourceFromLocal; - // No data in the URL and no data in the localStorage to fallback to. - // Initialize with the default store. + /** + * No data in the URL and no data in the localStorage to fallback to. + * Initialize with the default store. + */ if (!encodedSource) return defaultStore; const raw = decodeStore(encodedSource); diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index 637f300ae1538..c3f57499ce4d6 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -3,24 +3,27 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "NODE_ENV=development next dev", - "build": "next build && node ./scripts/downloadFonts.js", - "vercel-build": "yarn workspaces run build", + "dev": "cd ../.. && concurrently --kill-others -n compiler,runtime,playground \"yarn workspace babel-plugin-react-compiler run build --watch\" \"yarn workspace react-compiler-runtime run build --watch\" \"wait-on packages/babel-plugin-react-compiler/dist/index.js && cd apps/playground && NODE_ENV=development next dev\"", + "build:compiler": "cd ../.. && concurrently -n compiler,runtime \"yarn workspace babel-plugin-react-compiler run build\" \"yarn workspace react-compiler-runtime run build\"", + "build": "yarn build:compiler && next build", + "postbuild": "node ./scripts/downloadFonts.js", + "postinstall": "./scripts/link-compiler.sh", + "vercel-build": "yarn build", "start": "next start", "lint": "next lint", "test": "playwright test" }, "dependencies": { - "@babel/core": "^7.19.1", - "@babel/generator": "^7.19.1", - "@babel/parser": "^7.19.1", - "@babel/plugin-syntax-typescript": "^7.18.6", + "@babel/core": "^7.18.9", + "@babel/generator": "^7.18.9", + "@babel/parser": "^7.18.9", + "@babel/plugin-syntax-typescript": "^7.18.9", "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0", + "@babel/plugin-transform-modules-commonjs": "^7.18.9", + "@babel/preset-react": "^7.18.9", + "@babel/preset-typescript": "^7.18.9", + "@babel/traverse": "^7.18.9", + "@babel/types": "7.18.9", "@heroicons/react": "^1.0.6", "@monaco-editor/react": "^4.4.6", "@playwright/test": "^1.42.1", @@ -36,25 +39,23 @@ "prettier": "^3.3.3", "pretty-format": "^29.3.1", "re-resizable": "^6.9.16", - "react": "18.2.0", + "react": "18.3.1", "react-compiler-runtime": "*", - "react-dom": "18.2.0" + "react-dom": "18.3.1" }, "devDependencies": { "@types/node": "18.11.9", - "@types/react": "18.0.25", - "@types/react-dom": "18.0.9", + "@types/react": "18.3.9", + "@types/react-dom": "18.3.0", "autoprefixer": "^10.4.13", "clsx": "^1.2.1", + "concurrently": "^7.4.0", "eslint": "^8.28.0", "eslint-config-next": "^13.5.6", "hermes-parser": "^0.22.0", "monaco-editor-webpack-plugin": "^7.1.0", "postcss": "^8.4.31", - "tailwindcss": "^3.2.4" - }, - "resolutions": { - "./**/@babel/parser": "7.7.4", - "./**/@babel/types": "7.7.4" + "tailwindcss": "^3.2.4", + "wait-on": "^7.2.0" } } diff --git a/compiler/apps/playground/playwright.config.js b/compiler/apps/playground/playwright.config.js index be7010feb9c5a..d620a377460dc 100644 --- a/compiler/apps/playground/playwright.config.js +++ b/compiler/apps/playground/playwright.config.js @@ -30,8 +30,7 @@ export default defineConfig({ // Run your local dev server before starting the tests: // https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests webServer: { - command: - 'yarn workspace babel-plugin-react-compiler build && yarn workspace react-compiler-runtime build && yarn dev', + command: 'yarn dev', url: baseURL, timeout: 300 * 1000, reuseExistingServer: !process.env.CI, diff --git a/compiler/apps/playground/scripts/link-compiler.sh b/compiler/apps/playground/scripts/link-compiler.sh new file mode 100755 index 0000000000000..1ee5f0b81bf09 --- /dev/null +++ b/compiler/apps/playground/scripts/link-compiler.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# 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. + +set -eo pipefail + +HERE=$(pwd) + +cd ../../packages/react-compiler-runtime && yarn --silent link && cd $HERE +cd ../../packages/babel-plugin-react-compiler && yarn --silent link && cd $HERE + +yarn --silent link babel-plugin-react-compiler +yarn --silent link react-compiler-runtime diff --git a/compiler/apps/playground/tsconfig.json b/compiler/apps/playground/tsconfig.json index 55d0b209b9529..eb7fcfe2b7228 100644 --- a/compiler/apps/playground/tsconfig.json +++ b/compiler/apps/playground/tsconfig.json @@ -31,6 +31,7 @@ ".next/types/**/*.ts" ], "exclude": [ - "node_modules" + "node_modules", + "../../../**" ] } diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock new file mode 100644 index 0000000000000..716649103e6af --- /dev/null +++ b/compiler/apps/playground/yarn.lock @@ -0,0 +1,3653 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== + +"@babel/core@^7.18.9": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.18.9", "@babel/generator@^7.25.0", "@babel/generator@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" + integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== + dependencies: + "@babel/types" "^7.25.6" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab" + integrity sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== + dependencies: + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.25.0": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz#57eaf1af38be4224a9d9dd01ddde05b741f50e14" + integrity sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/helper-replace-supers" "^7.25.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/traverse" "^7.25.4" + semver "^6.3.1" + +"@babel/helper-member-expression-to-functions@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz#6155e079c913357d24a4c20480db7c712a5c3fb6" + integrity sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA== + dependencies: + "@babel/traverse" "^7.24.8" + "@babel/types" "^7.24.8" + +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-module-transforms@^7.24.8", "@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== + dependencies: + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" + +"@babel/helper-optimise-call-expression@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz#8b0a0456c92f6b323d27cfd00d1d664e76692a0f" + integrity sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878" + integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg== + +"@babel/helper-replace-supers@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz#ff44deac1c9f619523fe2ca1fd650773792000a9" + integrity sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.24.8" + "@babel/helper-optimise-call-expression" "^7.24.7" + "@babel/traverse" "^7.25.0" + +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz#5f8fa83b69ed5c27adc56044f8be2b3ea96669d9" + integrity sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ== + dependencies: + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" + +"@babel/helper-string-parser@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" + integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/helper-validator-option@^7.24.7", "@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== + +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== + dependencies: + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.18.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== + dependencies: + "@babel/types" "^7.25.6" + +"@babel/plugin-syntax-jsx@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d" + integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-syntax-typescript@^7.18.9", "@babel/plugin-syntax-typescript@^7.24.7": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff" + integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-transform-block-scoping@^7.18.9": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz#23a6ed92e6b006d26b1869b1c91d1b917c2ea2ac" + integrity sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.8" + +"@babel/plugin-transform-modules-commonjs@^7.18.9", "@babel/plugin-transform-modules-commonjs@^7.24.7": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz#ab6421e564b717cb475d6fff70ae7f103536ea3c" + integrity sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA== + dependencies: + "@babel/helper-module-transforms" "^7.24.8" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-simple-access" "^7.24.7" + +"@babel/plugin-transform-react-display-name@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz#9caff79836803bc666bcfe210aeb6626230c293b" + integrity sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-react-jsx-development@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.24.7.tgz#eaee12f15a93f6496d852509a850085e6361470b" + integrity sha512-QG9EnzoGn+Qar7rxuW+ZOsbWOt56FvvI93xInqsZDC5fsekx1AlIO4KIJ5M+D0p0SqSH156EpmZyXq630B8OlQ== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.24.7" + +"@babel/plugin-transform-react-jsx@^7.24.7": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz#e37e8ebfa77e9f0b16ba07fadcb6adb47412227a" + integrity sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/plugin-syntax-jsx" "^7.24.7" + "@babel/types" "^7.25.2" + +"@babel/plugin-transform-react-pure-annotations@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.7.tgz#bdd9d140d1c318b4f28b29a00fb94f97ecab1595" + integrity sha512-PLgBVk3fzbmEjBJ/u8kFzOqS9tUeDjiaWud/rRym/yjCo/M9cASPlnrd2ZmmZpQT40fOOrvR8jh+n8jikrOhNA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-plugin-utils" "^7.24.7" + +"@babel/plugin-transform-typescript@^7.24.7": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz#237c5d10de6d493be31637c6b9fa30b6c5461add" + integrity sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.24.7" + "@babel/helper-create-class-features-plugin" "^7.25.0" + "@babel/helper-plugin-utils" "^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers" "^7.24.7" + "@babel/plugin-syntax-typescript" "^7.24.7" + +"@babel/preset-react@^7.18.9": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.24.7.tgz#480aeb389b2a798880bf1f889199e3641cbb22dc" + integrity sha512-AAH4lEkpmzFWrGVlHaxJB7RLH21uPQ9+He+eFLWHmF9IuFQVugz8eAsamaW0DXRrTfco5zj1wWtpdcXJUOfsag== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + "@babel/plugin-transform-react-display-name" "^7.24.7" + "@babel/plugin-transform-react-jsx" "^7.24.7" + "@babel/plugin-transform-react-jsx-development" "^7.24.7" + "@babel/plugin-transform-react-pure-annotations" "^7.24.7" + +"@babel/preset-typescript@^7.18.9": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.24.7.tgz#66cd86ea8f8c014855671d5ea9a737139cbbfef1" + integrity sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ== + dependencies: + "@babel/helper-plugin-utils" "^7.24.7" + "@babel/helper-validator-option" "^7.24.7" + "@babel/plugin-syntax-jsx" "^7.24.7" + "@babel/plugin-transform-modules-commonjs" "^7.24.7" + "@babel/plugin-transform-typescript" "^7.24.7" + +"@babel/runtime@^7.21.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" + +"@babel/traverse@^7.18.9", "@babel/traverse@^7.24.7", "@babel/traverse@^7.24.8", "@babel/traverse@^7.25.0", "@babel/traverse@^7.25.2", "@babel/traverse@^7.25.4": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" + integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.6" + "@babel/parser" "^7.25.6" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f" + integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@babel/types@^7.24.7", "@babel/types@^7.24.8", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== + dependencies: + "@babel/helper-string-parser" "^7.24.8" + "@babel/helper-validator-identifier" "^7.24.7" + to-fast-properties "^2.0.0" + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.6.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@heroicons/react@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324" + integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ== + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@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== + 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== + dependencies: + "@monaco-editor/loader" "^1.4.0" + +"@next/env@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.7.tgz#5006f4460a7fa598a03e1c2aa4e59e45c71082d3" + integrity sha512-uVuRqoj28Ys/AI/5gVEgRAISd0KWI0HRjOO1CTpNgmX3ZsHb5mdn14Y59yk0IxizXdo7ZjsI2S7qbWnO+GNBcA== + +"@next/eslint-plugin-next@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.7.tgz#9a8cd86a7a27b8f370ec3b130e598688c869bdc6" + integrity sha512-c4vuEOOXeib4js5gDq+zFqAAdRGXX6T0d+zFETiQkRwy7vyj5lBov1dW0Z09nDst2lvxo7VEcKrQMUBH5Vgx7Q== + dependencies: + glob "7.1.7" + +"@next/swc-darwin-arm64@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.7.tgz#b99b91c04a884ba1272a3bd5db2b6f47a5bb10c2" + integrity sha512-7SxmxMex45FvKtRoP18eftrDCMyL6WQVYJSEE/s7A1AW/fCkznxjEShKet2iVVzf89gWp8HbXGaL4hCaseux6g== + +"@next/swc-darwin-x64@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.7.tgz#0a30d1c40430ed09ef4384bd90148e68badbf5e5" + integrity sha512-6iENvgyIkGFLFszBL4b1VfEogKC3TDPEB6/P/lgxmgXVXIV09Q4or1MVn+U/tYyYmm7oHMZ3oxGpHAyJ80nA6g== + +"@next/swc-linux-arm64-gnu@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.7.tgz#f6464e423186494d44ae9544c76b50e661682bc0" + integrity sha512-P42jDX56wu9zEdVI+Xv4zyTeXB3DpqgE1Gb4bWrc0s2RIiDYr6uKBprnOs1hCGIwfVyByxyTw5Va66QCdFFNUg== + +"@next/swc-linux-arm64-musl@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.7.tgz#88b62e006d00fc31359723f96cbd601132812873" + integrity sha512-A06vkj+8X+tLRzSja5REm/nqVOCzR+x5Wkw325Q/BQRyRXWGCoNbQ6A+BR5M86TodigrRfI3lUZEKZKe3QJ9Bg== + +"@next/swc-linux-x64-gnu@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.7.tgz#68d31a7c75f1b0dbc408f9fe49ac878c6723446c" + integrity sha512-UdHm7AlxIbdRdMsK32cH0EOX4OmzAZ4Xm+UVlS0YdvwLkI3pb7AoBEoVMG5H0Wj6Wpz6GNkrFguHTRLymTy6kw== + +"@next/swc-linux-x64-musl@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.7.tgz#09c9c3c667abd55f2af0b4e464342350baeabdb3" + integrity sha512-c50Y8xBKU16ZGj038H6C13iedRglxvdQHD/1BOtes56gwUrIRDX2Nkzn3mYtpz3Wzax0gfAF9C0Nqljt93IxvA== + +"@next/swc-win32-arm64-msvc@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.7.tgz#3314966f960a22ee95adb8285e0927c9e4ba7205" + integrity sha512-NcUx8cmkA+JEp34WNYcKW6kW2c0JBhzJXIbw+9vKkt9m/zVJ+KfizlqmoKf04uZBtzFN6aqE2Fyv2MOd021WIA== + +"@next/swc-win32-ia32-msvc@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.7.tgz#fd118f3bd5a87453b252eb3c5fae54ddce035026" + integrity sha512-wXp+/3NVcuyJDED6gJiLXs5dqHaWO7moAB6aBtjlKZvsxBDxpcyjsfRbtHPeYtaT20zCkmPs69H0K25lrVZmlA== + +"@next/swc-win32-x64-msvc@13.5.7": + version "13.5.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.7.tgz#3eff03a5a80281449c58fece85a780c1e6e3594b" + integrity sha512-PLyD3Dl6jTTkLG8AoqhPGd5pXtSs8wbqIhWPQt3yEMfnYld/dGYuF2YPs3YHaVFrijCIF9pXY3+QOyvP23Zn7g== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@playwright/test@^1.42.1": + version "1.47.2" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.47.2.tgz#dbe7051336bfc5cc599954214f9111181dbc7475" + integrity sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ== + dependencies: + playwright "1.47.2" + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + +"@rushstack/eslint-patch@^1.3.3": + version "1.10.4" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz#427d5549943a9c6fce808e39ea64dbe60d4047f1" + integrity sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA== + +"@sideway/address@^4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@swc/helpers@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d" + integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw== + dependencies: + tslib "^2.4.0" + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/node@18.11.9": + version "18.11.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" + integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== + +"@types/prop-types@*": + version "15.7.13" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== + +"@types/react-dom@18.3.0": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@18.3.9": + version "18.3.9" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.9.tgz#2cdf5f425ec8a133d67e9e3673909738b783db20" + integrity sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@typescript-eslint/parser@^5.4.2 || ^6.0.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== + +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@use-gesture/core@10.3.1": + version "10.3.1" + resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.3.1.tgz#976c9421e905f0079d49822cfd5c2e56b808fc56" + integrity sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw== + +"@use-gesture/react@^10.2.22": + version "10.3.1" + resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.3.1.tgz#17a743a894d9bd9a0d1980c618f37f0164469867" + integrity sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g== + dependencies: + "@use-gesture/core" "10.3.1" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.9.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +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== + +aria-query@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== + dependencies: + deep-equal "^2.0.5" + +array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.6, array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +autoprefixer@^10.4.13: + version "10.4.20" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b" + integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g== + dependencies: + browserslist "^4.23.3" + caniuse-lite "^1.0.30001646" + fraction.js "^4.3.7" + normalize-range "^0.1.2" + picocolors "^1.0.1" + postcss-value-parser "^4.2.0" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axe-core@^4.10.0: + version "4.10.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59" + integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g== + +axios@^1.6.1: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.23.1, browserslist@^4.23.3: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.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== + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663: + version "1.0.30001664" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz#d588d75c9682d3301956b05a3749652a80677df4" + integrity sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clsx@^1.1.0, clsx@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concurrently@^7.4.0: + version "7.6.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.6.0.tgz#531a6f5f30cf616f355a4afb8f8fcb2bba65a49a" + integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw== + dependencies: + chalk "^4.1.0" + date-fns "^2.29.1" + lodash "^4.17.21" + rxjs "^7.0.0" + shell-quote "^1.7.3" + spawn-command "^0.0.2-1" + supports-color "^8.1.0" + tree-kill "^1.2.2" + yargs "^17.3.1" + +convert-source-map@^2.0.0: + version "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== + +cross-spawn@^7.0.0, cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +date-fns@^2.29.1: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +deep-equal@^2.0.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.5" + es-get-iterator "^1.1.3" + get-intrinsic "^1.2.2" + is-arguments "^1.1.1" + is-array-buffer "^3.0.2" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.13" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.5.28: + version "1.5.29" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz#aa592a3caa95d07cc26a66563accf99fa573a1ee" + integrity sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +enhanced-resolve@^5.15.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-get-iterator@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + +es-iterator-helpers@^1.0.19: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + iterator.prototype "^1.1.2" + safe-array-concat "^1.1.2" + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1, escalade@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-next@^13.5.6: + version "13.5.7" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.5.7.tgz#fc5d86b22364c93d9279acab2a6f4848c4dbccaf" + integrity sha512-pdeUuL9KZ8qFzzKqCbxk6FXwG9dNEnot/3+qSFJqxdSGgkFUH8cgZus/meyCi2S0cTAsDbBEE030E6zvL9pUYQ== + dependencies: + "@next/eslint-plugin-next" "13.5.7" + "@rushstack/eslint-patch" "^1.3.3" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.28.1" + eslint-plugin-jsx-a11y "^6.7.1" + eslint-plugin-react "^7.33.2" + eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.5.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz#bb8e388f6afc0f940ce5d2c5fd4a3d147f038d9e" + integrity sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.5" + enhanced-resolve "^5.15.0" + eslint-module-utils "^2.8.1" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" + is-glob "^4.0.3" + +eslint-module-utils@^2.8.1, eslint-module-utils@^2.9.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.28.1: + version "2.30.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449" + integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.9.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + tsconfig-paths "^3.15.0" + +eslint-plugin-jsx-a11y@^6.7.1: + version "6.10.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz#36fb9dead91cafd085ddbe3829602fb10ef28339" + integrity sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg== + dependencies: + aria-query "~5.1.3" + array-includes "^3.1.8" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "^4.10.0" + axobject-query "^4.1.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + es-iterator-helpers "^1.0.19" + hasown "^2.0.2" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.0" + +"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": + version "4.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== + +eslint-plugin-react@^7.33.2: + version "7.36.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz#f1dabbb11f3d4ebe8b0cf4e54aff4aee81144ee5" + integrity sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.2" + array.prototype.tosorted "^1.1.4" + doctrine "^2.1.0" + es-iterator-helpers "^1.0.19" + estraverse "^5.3.0" + hasown "^2.0.2" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.8" + object.fromentries "^2.0.8" + object.values "^1.2.0" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.11" + string.prototype.repeat "^1.0.0" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.28.0: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fraction.js@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fs@^0.0.1-security: + version "0.0.1-security" + resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" + integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== + +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + +get-tsconfig@^4.7.5: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +goober@^2.0.33: + version "2.1.14" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.14.tgz#4a5c94fc34dc086a8e6035360ae1800005135acd" + integrity sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg== + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hermes-eslint@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.14.0.tgz#d56426b0931a7ced99d08b4b6a06f798064b13ba" + integrity sha512-ORk7znDabvALzTbI3QRIQefCkxF1ukDm3dVut3e+cVmwdtsTC71BJetSvdh1jtgK10czwck1QiPZOVOVolhiqQ== + dependencies: + esrecurse "^4.3.0" + hermes-estree "0.14.0" + hermes-parser "0.14.0" + +hermes-estree@0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.14.0.tgz#c663eea1400980802283338a09d0087c448729e7" + integrity sha512-L6M67+0/eSEbt6Ha2XOBFXL++7MR34EOJMgm+j7YCaI4L/jZqrVAg6zYQKzbs1ZCFDLvEQpOgLlapTX4gpFriA== + +hermes-estree@0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.22.0.tgz#38559502b119f728901d2cfe2ef422f277802a1d" + integrity sha512-FLBt5X9OfA8BERUdc6aZS36Xz3rRuB0Y/mfocSADWEJfomc1xfene33GdyAmtTkKTBXTN/EgAy+rjTKkkZJHlw== + +hermes-parser@0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.14.0.tgz#edb2e7172fce996d2c8bbba250d140b70cc1aaaf" + integrity sha512-pt+8uRiJhVlErY3fiXB3gKhZ72RxM6E1xRMpvfZ5n6Z5TQKQQXKorgRCRzoe02mmvLKBJFP5nPDGv75MWAgCTw== + dependencies: + hermes-estree "0.14.0" + +hermes-parser@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.22.0.tgz#fc8e0e6c7bfa8db85b04c9f9544a102c4fcb4040" + integrity sha512-gn5RfZiEXCsIWsFGsKiykekktUoh0PdFWYocXsUdZIyWSckT6UIyPcyyUIPSR3kpnELWeK3n3ztAse7Mat6PSA== + dependencies: + hermes-estree "0.22.0" + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + 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" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.4, internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +is-arguments@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-bun-module@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.2.1.tgz#495e706f42e29f086fd5fe1ac3c51f106062b9fc" + integrity sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q== + dependencies: + semver "^7.6.3" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + +is-date-object@^1.0.1, is-date-object@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jiti@^1.21.0: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== + +joi@^17.11.0: + version "17.13.3" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" + integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA== + dependencies: + "@hapi/hoek" "^9.3.0" + "@hapi/topo" "^5.1.0" + "@sideway/address" "^4.1.5" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", 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@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, 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== + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +language-subtag-registry@^0.3.20: + version "0.3.23" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== + +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + dependencies: + language-subtag-registry "^0.3.20" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lilconfig@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== + +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== + +loader-utils@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lz-string@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +monaco-editor-webpack-plugin@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.1.0.tgz#16f265c2b5dbb5fe08681b6b3b7d00d3c5b2ee97" + integrity sha512-ZjnGINHN963JQkFqjjcBtn1XBtUATDZBMgNQhDQwd78w2ukRhFXAPNgWuacaQiDZsUr4h1rWv5Mv6eriKuOSzA== + dependencies: + loader-utils "^2.0.2" + +monaco-editor@^0.34.1: + version "0.34.1" + resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87" + integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ== + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanoid@^3.3.6, nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +next@^13.5.6: + version "13.5.7" + resolved "https://registry.yarnpkg.com/next/-/next-13.5.7.tgz#deddbb6644b235f0f6be2bbb6facce9ce004fd8e" + integrity sha512-W7KIRTE+hPcgGdq89P3mQLDX3m7pJ6nxSyC+YxYaUExE+cS4UledB+Ntk98tKoyhsv6fjb2TRAnD7VDvoqmeFg== + dependencies: + "@next/env" "13.5.7" + "@swc/helpers" "0.5.2" + busboy "1.6.0" + caniuse-lite "^1.0.30001406" + postcss "8.4.31" + styled-jsx "5.1.1" + watchpack "2.4.0" + optionalDependencies: + "@next/swc-darwin-arm64" "13.5.7" + "@next/swc-darwin-x64" "13.5.7" + "@next/swc-linux-arm64-gnu" "13.5.7" + "@next/swc-linux-arm64-musl" "13.5.7" + "@next/swc-linux-x64-gnu" "13.5.7" + "@next/swc-linux-x64-musl" "13.5.7" + "@next/swc-win32-arm64-msvc" "13.5.7" + "@next/swc-win32-ia32-msvc" "13.5.7" + "@next/swc-win32-x64-msvc" "13.5.7" + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +notistack@^3.0.0-alpha.7: + version "3.0.1" + resolved "https://registry.yarnpkg.com/notistack/-/notistack-3.0.1.tgz#daf59888ab7e2c30a1fa8f71f9cba2978773236e" + integrity sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA== + dependencies: + clsx "^1.1.0" + goober "^2.0.33" + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4, object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.1.6, object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +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" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pirates@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +playwright-core@1.47.2: + version "1.47.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.47.2.tgz#7858da9377fa32a08be46ba47d7523dbd9460a4e" + integrity sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ== + +playwright@1.47.2: + version "1.47.2" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.47.2.tgz#155688aa06491ee21fb3e7555b748b525f86eb20" + integrity sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA== + dependencies: + playwright-core "1.47.2" + optionalDependencies: + fsevents "2.3.2" + +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== + dependencies: + camelcase-css "^2.0.1" + +postcss-load-config@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3" + integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ== + dependencies: + lilconfig "^3.0.0" + yaml "^2.3.4" + +postcss-nested@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131" + integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ== + dependencies: + postcss-selector-parser "^6.1.1" + +postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.1.1: + version "6.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" + integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.23, postcss@^8.4.31: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.0" + source-map-js "^1.2.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + +pretty-format@^29.3.1: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +re-resizable@^6.9.16: + version "6.10.0" + resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee" + integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw== + +react-compiler-runtime@*: + version "0.0.0" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0.tgz#906990637c0f367f836746931f4824b2acf8a05c" + integrity sha512-ZaNBKRbqg6eZc+YKtJ3MeOwUJ/XjBnEzYnUURWTcvOFGlA79g45QFj7bbVP2ITeUPkiY2PsZZu+NmFEje4p0RA== + +react-dom@18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +react@18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== + dependencies: + pify "^2.3.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reflect.getprototypeof@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== + dependencies: + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +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== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.1.7, resolve@^1.22.2, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.0.0, rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" + +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.4, semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1, set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-js@^1.0.2, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +spawn-command@^0.0.2-1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" + integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== + +state-local@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5" + integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w== + +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +"string-width-cjs@npm:string-width@^4.2.0": + 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@^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" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.includes@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz#8986d57aee66d5460c144620a6d873778ad7289f" + integrity sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.matchall@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" + +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +"strip-ansi-cjs@npm: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@^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" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +styled-jsx@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" + integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== + dependencies: + client-only "0.0.1" + +sucrase@^3.32.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tailwindcss@^3.2.4: + version "3.4.13" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.13.tgz#3d11e5510660f99df4f1bfb2d78434666cb8f831" + integrity sha512-KqjHOJKogOUt5Bs752ykCeiwvi0fKVkr5oqsFNt/8px/tA8scFPIlkygsf6jXrfCqGHz7VflA6+yytWuM+XhFw== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.21.0" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +ts-api-utils@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.1.0, tslib@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== + dependencies: + escalade "^3.1.2" + picocolors "^1.0.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +wait-on@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-7.2.0.tgz#d76b20ed3fc1e2bebc051fae5c1ff93be7892928" + integrity sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ== + dependencies: + axios "^1.6.1" + joi "^17.11.0" + lodash "^4.17.21" + minimist "^1.2.8" + rxjs "^7.8.1" + +watchpack@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-builtin-type@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.4.tgz#592796260602fc3514a1b5ee7fa29319b72380c3" + integrity sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w== + dependencies: + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.2" + which-typed-array "^1.1.15" + +which-collection@^1.0.1, which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +"wrap-ansi-cjs@npm: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@^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" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^2.3.4: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.1.tgz#c9772aacf62cb7494a95b0c4f1fb065b563db130" + integrity sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/compiler/package.json b/compiler/package.json index 2d898b1305b9f..12c6de56dc0c6 100644 --- a/compiler/package.json +++ b/compiler/package.json @@ -2,12 +2,7 @@ "private": true, "workspaces": { "packages": [ - "packages/*", - "apps/*" - ], - "nohoist": [ - "**/next", - "**/next/**" + "packages/*" ] }, "repository": { @@ -20,11 +15,11 @@ "start": "yarn workspace playground run start", "next": "yarn workspace playground run dev", "build": "yarn workspaces run build", - "dev": "concurrently --kill-others -n compiler,runtime,playground \"yarn workspace babel-plugin-react-compiler run build --watch\" \"yarn workspace react-compiler-runtime run build --watch\" \"wait-on packages/babel-plugin-react-compiler/dist/index.js && yarn workspace playground run dev\"", + "dev": "echo 'DEPRECATED: use `cd apps/playground && yarn dev` instead!' && sleep 5 && cd apps/playground && yarn dev", "test": "yarn workspaces run test", "snap": "yarn workspace babel-plugin-react-compiler run snap", "snap:build": "yarn workspace snap run build", - "postinstall": "perl -p -i -e 's/react\\.element/react.transitional.element/' packages/snap/node_modules/fbt/lib/FbtReactUtil.js && perl -p -i -e 's/didWarnAboutUsingAct = false;/didWarnAboutUsingAct = true;/' packages/babel-plugin-react-compiler/node_modules/react-dom/cjs/react-dom-test-utils.development.js", + "postinstall": "perl -p -i -e 's/react\\.element/react.transitional.element/' node_modules/fbt/lib/FbtReactUtil.js && perl -p -i -e 's/didWarnAboutUsingAct = false;/didWarnAboutUsingAct = true;/' node_modules/react-dom/cjs/react-dom-test-utils.development.js", "npm:publish": "node scripts/release/publish" }, "dependencies": { @@ -39,6 +34,7 @@ "@tsconfig/strictest": "^2.0.5", "concurrently": "^7.4.0", "folder-hash": "^4.0.4", + "object-assign": "^4.1.1", "ora": "5.4.1", "prettier": "^3.3.3", "prettier-plugin-hermes-parser": "^0.23.0", diff --git a/compiler/packages/babel-plugin-react-compiler/package.json b/compiler/packages/babel-plugin-react-compiler/package.json index c8d9f8b17bc96..fa8d5c06cf4d7 100644 --- a/compiler/packages/babel-plugin-react-compiler/package.json +++ b/compiler/packages/babel-plugin-react-compiler/package.json @@ -41,12 +41,12 @@ "@types/invariant": "^2.2.35", "@types/jest": "^29.0.3", "@types/node": "^18.7.18", - "@typescript-eslint/eslint-plugin": "^7.4.0", - "@typescript-eslint/parser": "^7.4.0", + "@typescript-eslint/eslint-plugin": "^8.7.0", + "@typescript-eslint/parser": "^8.7.0", "babel-jest": "^29.0.3", "babel-plugin-fbt": "^1.0.0", "babel-plugin-fbt-runtime": "^1.0.0", - "eslint": "8.27.0", + "eslint": "^8.57.1", "glob": "^7.1.6", "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", diff --git a/compiler/packages/snap/package.json b/compiler/packages/snap/package.json index 5cc4eca5003d4..ed0b2dd6438a1 100644 --- a/compiler/packages/snap/package.json +++ b/compiler/packages/snap/package.json @@ -28,7 +28,7 @@ "babel-plugin-idx": "^3.0.3", "babel-plugin-syntax-hermes-parser": "^0.15.1", "chalk": "4", - "fbt": "^1.0.0", + "fbt": "^1.0.2", "glob": "^10.3.10", "hermes-parser": "^0.19.1", "jsdom": "^22.1.0", @@ -50,6 +50,7 @@ "@types/node": "^18.7.18", "@typescript-eslint/eslint-plugin": "^7.4.0", "@typescript-eslint/parser": "^7.4.0", + "object-assign": "^4.1.1", "rimraf": "^3.0.2" }, "resolutions": { diff --git a/compiler/yarn.lock b/compiler/yarn.lock index 76f33a20adeb8..8f4f318e7f826 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -7,11 +7,6 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@alloc/quick-lru@^5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" - integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== - "@ampproject/remapping@^2.2.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" @@ -41,12 +36,12 @@ dependencies: "@babel/highlight" "^7.22.5" -"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== +"@babel/code-frame@^7.24.7", "@babel/code-frame@^7.5.5": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== dependencies: - "@babel/highlight" "^7.24.2" + "@babel/highlight" "^7.24.7" picocolors "^1.0.0" "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.22.0", "@babel/compat-data@^7.22.3": @@ -54,10 +49,10 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.3.tgz#cd502a6a0b6e37d7ad72ce7e71a7160a3ae36f7e" integrity sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ== -"@babel/compat-data@^7.23.5": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" - integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== +"@babel/compat-data@^7.25.2": + version "7.25.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" + integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== "@babel/core@^7.0.0", "@babel/core@^7.2.0": version "7.2.0" @@ -80,27 +75,27 @@ source-map "^0.5.0" "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.19.1", "@babel/core@^7.24.4": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.5.tgz#15ab5b98e101972d171aeef92ac70d8d6718f06a" - integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" + integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.24.5" - "@babel/helpers" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.0" + "@babel/helper-compilation-targets" "^7.25.2" + "@babel/helper-module-transforms" "^7.25.2" + "@babel/helpers" "^7.25.0" + "@babel/parser" "^7.25.0" + "@babel/template" "^7.25.0" + "@babel/traverse" "^7.25.2" + "@babel/types" "^7.25.2" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@7.2.0", "@babel/generator@^7.0.0", "@babel/generator@^7.1.6", "@babel/generator@^7.2.0": +"@babel/generator@7.2.0", "@babel/generator@^7.0.0", "@babel/generator@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== @@ -111,22 +106,12 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.19.1": - version "7.24.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.9.tgz#5c2575a1070e661bbbc9df82a853989c9a656f12" - integrity sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A== - dependencies: - "@babel/types" "^7.24.9" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" - -"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" - integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== +"@babel/generator@^7.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" + integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== dependencies: - "@babel/types" "^7.24.5" + "@babel/types" "^7.25.6" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" @@ -163,14 +148,14 @@ lru-cache "^5.1.1" semver "^6.3.0" -"@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" + integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.2" + "@babel/helper-validator-option" "^7.24.8" + browserslist "^4.23.1" lru-cache "^5.1.1" semver "^6.3.1" @@ -248,24 +233,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz#ac3a56dbada59ed969d712cf527bd8271fe3eba8" integrity sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA== -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - "@babel/helper-environment-visitor@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== -"@babel/helper-function-name@^7.1.0", "@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - "@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" @@ -290,6 +262,14 @@ "@babel/template" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/helper-function-name@^7.7.4": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== + dependencies: + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" @@ -297,13 +277,6 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - "@babel/helper-member-expression-to-functions@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" @@ -339,12 +312,13 @@ dependencies: "@babel/types" "^7.21.4" -"@babel/helper-module-imports@^7.24.3": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== +"@babel/helper-module-imports@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" + integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== dependencies: - "@babel/types" "^7.24.0" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" "@babel/helper-module-transforms@^7.18.6": version "7.19.0" @@ -388,16 +362,15 @@ "@babel/traverse" "^7.21.2" "@babel/types" "^7.21.2" -"@babel/helper-module-transforms@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz#ea6c5e33f7b262a0ae762fd5986355c45f54a545" - integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== +"@babel/helper-module-transforms@^7.25.2": + version "7.25.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" + integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.24.3" - "@babel/helper-simple-access" "^7.24.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/helper-validator-identifier" "^7.24.5" + "@babel/helper-module-imports" "^7.24.7" + "@babel/helper-simple-access" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.7" + "@babel/traverse" "^7.25.2" "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" @@ -496,12 +469,13 @@ dependencies: "@babel/types" "^7.21.5" -"@babel/helper-simple-access@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz#50da5b72f58c16b07fbd992810be6049478e85ba" - integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== +"@babel/helper-simple-access@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" + integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== dependencies: - "@babel/types" "^7.24.5" + "@babel/traverse" "^7.24.7" + "@babel/types" "^7.24.7" "@babel/helper-skip-transparent-expression-wrappers@^7.20.0": version "7.20.0" @@ -517,13 +491,6 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-split-export-declaration@^7.0.0", "@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - "@babel/helper-split-export-declaration@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" @@ -531,12 +498,19 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-split-export-declaration@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6" - integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.7.4": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== dependencies: - "@babel/types" "^7.24.5" + "@babel/types" "^7.24.7" "@babel/helper-string-parser@^7.18.10": version "7.18.10" @@ -558,11 +532,6 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-string-parser@^7.23.4", "@babel/helper-string-parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== - "@babel/helper-string-parser@^7.24.8": version "7.24.8" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" @@ -573,21 +542,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - "@babel/helper-validator-identifier@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== -"@babel/helper-validator-identifier@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" - integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== - "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" @@ -608,10 +567,10 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== +"@babel/helper-validator-option@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" + integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== "@babel/helper-wrap-function@^7.18.9": version "7.20.5" @@ -632,14 +591,13 @@ "@babel/traverse" "^7.19.0" "@babel/types" "^7.19.0" -"@babel/helpers@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.5.tgz#fedeb87eeafa62b621160402181ad8585a22a40a" - integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== +"@babel/helpers@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" + integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.5" - "@babel/types" "^7.24.5" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" "@babel/highlight@^7.18.6": version "7.18.6" @@ -659,12 +617,12 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== dependencies: - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-validator-identifier" "^7.24.7" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" @@ -674,11 +632,6 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c" integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A== -"@babel/parser@^7.1.6", "@babel/parser@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" - integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== - "@babel/parser@^7.18.6": version "7.19.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a" @@ -699,15 +652,17 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== -"@babel/parser@^7.24.0": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" - integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== +"@babel/parser@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== -"@babel/parser@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" - integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== +"@babel/parser@^7.25.0", "@babel/parser@^7.25.6": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" + integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== + dependencies: + "@babel/types" "^7.25.6" "@babel/parser@^7.7.4": version "7.21.4" @@ -1547,7 +1502,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.21.0", "@babel/runtime@^7.8.4": version "7.22.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb" integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ== @@ -1581,15 +1536,6 @@ "@babel/parser" "^7.21.9" "@babel/types" "^7.21.5" -"@babel/template@^7.22.15", "@babel/template@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - "@babel/template@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" @@ -1599,6 +1545,15 @@ "@babel/parser" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/template@^7.24.7", "@babel/template@^7.25.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" + integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/parser" "^7.25.0" + "@babel/types" "^7.25.0" + "@babel/template@^7.3.3": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" @@ -1608,34 +1563,31 @@ "@babel/parser" "^7.18.6" "@babel/types" "^7.18.6" -"@babel/traverse@^7.1.6": - version "7.1.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.6.tgz#c8db9963ab4ce5b894222435482bd8ea854b7b5c" - integrity sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ== +"@babel/traverse@^7.1.6", "@babel/traverse@^7.2.0", "@babel/traverse@^7.7.2": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" + integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.6" - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.6" - "@babel/types" "^7.1.6" + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.4" + "@babel/helper-function-name" "^7.7.4" + "@babel/helper-split-export-declaration" "^7.7.4" + "@babel/parser" "^7.7.4" + "@babel/types" "^7.7.4" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.10" - -"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.2.0", "@babel/traverse@^7.20.5", "@babel/traverse@^7.21.2", "@babel/traverse@^7.22.1", "@babel/traverse@^7.24.5", "@babel/traverse@^7.7.2": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" - integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== - dependencies: - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.24.5" - "@babel/parser" "^7.24.5" - "@babel/types" "^7.24.5" + lodash "^4.17.13" + +"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.21.2", "@babel/traverse@^7.22.1", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" + integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== + dependencies: + "@babel/code-frame" "^7.24.7" + "@babel/generator" "^7.25.6" + "@babel/parser" "^7.25.6" + "@babel/template" "^7.25.0" + "@babel/types" "^7.25.6" debug "^4.3.1" globals "^11.1.0" @@ -1647,15 +1599,6 @@ "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" -"@babel/types@^7.1.6", "@babel/types@^7.23.0", "@babel/types@^7.24.0": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - "@babel/types@^7.18.10", "@babel/types@^7.19.0", "@babel/types@^7.2.0": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600" @@ -1701,19 +1644,10 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@babel/types@^7.24.5": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" - integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== - dependencies: - "@babel/helper-string-parser" "^7.24.1" - "@babel/helper-validator-identifier" "^7.24.5" - to-fast-properties "^2.0.0" - -"@babel/types@^7.24.9": - version "7.24.9" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.9.tgz#228ce953d7b0d16646e755acf204f4cf3d08cc73" - integrity sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ== +"@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.7.4": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" + integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== dependencies: "@babel/helper-string-parser" "^7.24.8" "@babel/helper-validator-identifier" "^7.24.7" @@ -1738,46 +1672,16 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" - integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== +"@eslint-community/regexpp@^4.10.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": version "4.10.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== -"@eslint/eslintrc@^1.3.3": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" - integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.4.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/eslintrc@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" - integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.5.2" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - "@eslint/eslintrc@^2.1.4": version "2.1.4" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" @@ -1793,16 +1697,16 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.41.0": - version "8.41.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.41.0.tgz#080321c3b68253522f7646b55b577dd99d2950b3" - integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA== - "@eslint/js@8.57.0": version "8.57.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -1815,11 +1719,6 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@heroicons/react@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324" - integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ== - "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -1829,22 +1728,13 @@ debug "^4.3.1" minimatch "^3.0.5" -"@humanwhocodes/config-array@^0.11.6": - version "0.11.13" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" - integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== - dependencies: - "@humanwhocodes/object-schema" "^2.0.1" - debug "^4.1.1" - minimatch "^3.0.5" - -"@humanwhocodes/config-array@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" - integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -1852,21 +1742,16 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@humanwhocodes/object-schema@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" - integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== - "@humanwhocodes/object-schema@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -2482,15 +2367,6 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jridgewell/gen-mapping@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" - integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -2510,11 +2386,6 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - "@jridgewell/set-array@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" @@ -2546,7 +2417,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15": version "0.3.15" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== @@ -2570,77 +2441,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@monaco-editor/loader@^1.3.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.3.tgz#7f1742bd3cc21c0362a46a4056317f6e5215cfca" - integrity sha512-6KKF4CTzcJiS8BJwtxtfyYt9shBiEv32ateQ9T4UVogwn4HM/uPo9iJd2Dmbkpz8CM6Y0PDUpjnZzCwC+eYo2Q== - dependencies: - state-local "^1.0.6" - -"@monaco-editor/react@^4.4.6": - version "4.5.1" - resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.5.1.tgz#fbc76c692aee9a33b9ab24ae0c5f219b8f002fdb" - integrity sha512-NNDFdP+2HojtNhCkRfE6/D6ro6pBNihaOzMbGK84lNWzRu+CfBjwzGt4jmnqimLuqp5yE5viHS2vi+QOAnD5FQ== - dependencies: - "@monaco-editor/loader" "^1.3.3" - -"@next/env@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.6.tgz#c1148e2e1aa166614f05161ee8f77ded467062bc" - integrity sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw== - -"@next/eslint-plugin-next@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.6.tgz#cf279b94ddc7de49af8e8957f0c3b7349bc489bf" - integrity sha512-ng7pU/DDsxPgT6ZPvuprxrkeew3XaRf4LAT4FabaEO/hAbvVx4P7wqnqdbTdDn1kgTvsI4tpIgT4Awn/m0bGbg== - dependencies: - glob "7.1.7" - -"@next/swc-darwin-arm64@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz#b15d139d8971360fca29be3bdd703c108c9a45fb" - integrity sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA== - -"@next/swc-darwin-x64@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz#9c72ee31cc356cb65ce6860b658d807ff39f1578" - integrity sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA== - -"@next/swc-linux-arm64-gnu@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz#59f5f66155e85380ffa26ee3d95b687a770cfeab" - integrity sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg== - -"@next/swc-linux-arm64-musl@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz#f012518228017052736a87d69bae73e587c76ce2" - integrity sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q== - -"@next/swc-linux-x64-gnu@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz#339b867a7e9e7ee727a700b496b269033d820df4" - integrity sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw== - -"@next/swc-linux-x64-musl@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz#ae0ae84d058df758675830bcf70ca1846f1028f2" - integrity sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ== - -"@next/swc-win32-arm64-msvc@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz#a5cc0c16920485a929a17495064671374fdbc661" - integrity sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg== - -"@next/swc-win32-ia32-msvc@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz#6a2409b84a2cbf34bf92fe714896455efb4191e4" - integrity sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg== - -"@next/swc-win32-x64-msvc@13.5.6": - version "13.5.6" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz#4a3e2a206251abc729339ba85f60bc0433c2865d" - integrity sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2677,25 +2477,6 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@pkgr/utils@^2.3.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.1.tgz#adf291d0357834c410ce80af16e711b56c7b1cd3" - integrity sha512-JOqwkgFEyi+OROIyq7l4Jy28h/WwhDnG/cPkXG2Z1iFbubB6jsHW1NDvmyOzTBxHr3yg68YGirmh1JUgMqa+9w== - dependencies: - cross-spawn "^7.0.3" - fast-glob "^3.2.12" - is-glob "^4.0.3" - open "^9.1.0" - picocolors "^1.0.0" - tslib "^2.5.0" - -"@playwright/test@^1.42.1": - version "1.42.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.42.1.tgz#9eff7417bcaa770e9e9a00439e078284b301f31c" - integrity sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ== - dependencies: - playwright "1.42.1" - "@rollup/plugin-commonjs@^25.0.7": version "25.0.7" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz#145cec7589ad952171aeb6a585bbeabd0fd3b4cf" @@ -2842,11 +2623,6 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== -"@rushstack/eslint-patch@^1.3.3": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922" - integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA== - "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" @@ -2902,13 +2678,6 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@swc/helpers@0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d" - integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw== - dependencies: - tslib "^2.4.0" - "@testing-library/dom@^8.5.0": version "8.18.1" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.18.1.tgz#80f91be02bc171fe5a3a7003f88207be31ac2cf3" @@ -3107,11 +2876,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - "@types/minimatch@^5.1.2": version "5.1.2" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" @@ -3122,11 +2886,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.19.tgz#ad83aa9b7af470fab7e0f562be87e97dc8ffe08e" integrity sha512-Sq1itGUKUX1ap7GgZlrzdBydjbsJL/NSQt/4wkAxUJ7/OS5c2WkoN6WSpWc2Yc5wtKMZOUA0VCs/j2XJadN3HA== -"@types/node@18.11.9": - version "18.11.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" - integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== - "@types/node@^20.2.5": version "20.2.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.5.tgz#26d295f3570323b2837d322180dfbf1ba156fefb" @@ -3149,13 +2908,6 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/react-dom@18.0.9": - version "18.0.9" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.9.tgz#ffee5e4bfc2a2f8774b15496474f8e7fe8d0b504" - integrity sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg== - dependencies: - "@types/react" "*" - "@types/react-dom@^18.0.0": version "18.0.6" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.6.tgz#36652900024842b74607a17786b6662dd1e103a1" @@ -3172,15 +2924,6 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@18.0.25": - version "18.0.25" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.25.tgz#8b1dcd7e56fe7315535a4af25435e0bb55c8ae44" - integrity sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - "@types/resolve@1.20.2": version "1.20.2" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" @@ -3242,16 +2985,20 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^5.4.2 || ^6.0.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb" - integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg== +"@typescript-eslint/eslint-plugin@^8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz#d0070f206daad26253bf00ca5b80f9b54f9e2dd0" + integrity sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A== dependencies: - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" - debug "^4.3.4" + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/type-utils" "8.7.0" + "@typescript-eslint/utils" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" "@typescript-eslint/parser@^7.4.0": version "7.4.0" @@ -3264,13 +3011,16 @@ "@typescript-eslint/visitor-keys" "7.4.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd" - integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g== +"@typescript-eslint/parser@^8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.7.0.tgz#a567b0890d13db72c7348e1d88442ea8ab4e9173" + integrity sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/typescript-estree" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + debug "^4.3.4" "@typescript-eslint/scope-manager@7.4.0": version "7.4.0" @@ -3280,6 +3030,14 @@ "@typescript-eslint/types" "7.4.0" "@typescript-eslint/visitor-keys" "7.4.0" +"@typescript-eslint/scope-manager@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz#90ee7bf9bc982b9260b93347c01a8bc2b595e0b8" + integrity sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg== + dependencies: + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + "@typescript-eslint/type-utils@7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz#cfcaab21bcca441c57da5d3a1153555e39028cbd" @@ -3290,28 +3048,25 @@ debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded" - integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ== +"@typescript-eslint/type-utils@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz#d56b104183bdcffcc434a23d1ce26cde5e42df93" + integrity sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ== + dependencies: + "@typescript-eslint/typescript-estree" "8.7.0" + "@typescript-eslint/utils" "8.7.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" "@typescript-eslint/types@7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.4.0.tgz#ee9dafa75c99eaee49de6dcc9348b45d354419b6" integrity sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw== -"@typescript-eslint/typescript-estree@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1" - integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg== - dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" +"@typescript-eslint/types@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.7.0.tgz#21d987201c07b69ce7ddc03451d7196e5445ad19" + integrity sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w== "@typescript-eslint/typescript-estree@7.4.0": version "7.4.0" @@ -3327,6 +3082,20 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz#6c7db6baa4380b937fa81466c546d052f362d0e8" + integrity sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg== + dependencies: + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/visitor-keys" "8.7.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/utils@7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.4.0.tgz#d889a0630cab88bddedaf7c845c64a00576257bd" @@ -3340,13 +3109,15 @@ "@typescript-eslint/typescript-estree" "7.4.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8" - integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg== +"@typescript-eslint/utils@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.7.0.tgz#cef3f70708b5b5fd7ed8672fc14714472bd8a011" + integrity sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw== dependencies: - "@typescript-eslint/types" "6.8.0" - eslint-visitor-keys "^3.4.1" + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.7.0" + "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/typescript-estree" "8.7.0" "@typescript-eslint/visitor-keys@7.4.0": version "7.4.0" @@ -3356,23 +3127,19 @@ "@typescript-eslint/types" "7.4.0" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@8.7.0": + version "8.7.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz#5e46f1777f9d69360a883c1a56ac3c511c9659a8" + integrity sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ== + dependencies: + "@typescript-eslint/types" "8.7.0" + eslint-visitor-keys "^3.4.3" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@use-gesture/core@10.2.27": - version "10.2.27" - resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.2.27.tgz#0f24b17c036cd828ba07e3451ff45e2df959c6f5" - integrity sha512-V4XV7hn9GAD2MYu8yBBVi5iuWBsAMfjPRMsEVzoTNGYH72tf0kFP+OKqGKc8YJFQIJx6yj+AOqxmEHOmx2/MEA== - -"@use-gesture/react@^10.2.22": - version "10.2.27" - resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.2.27.tgz#7fbd50d14449ec5bc49c9b6cfef8a2845f5e0608" - integrity sha512-7E5vnWCxeslWlxwZ8uKIcnUZVMTRMZ8cvSnLLKF1NkyNb3PnNiAzoXM4G1vTKJKRhgOTeI6wK1YsEpwo9ABV5w== - dependencies: - "@use-gesture/core" "10.2.27" - abab@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -3406,7 +3173,7 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.0: +acorn@^8.4.1, acorn@^8.7.1: version "8.8.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== @@ -3428,7 +3195,7 @@ agent-base@6: dependencies: debug "4" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -3484,11 +3251,6 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== - anymatch@^3.0.3: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -3497,24 +3259,11 @@ anymatch@^3.0.3: normalize-path "^3.0.0" picomatch "^2.0.4" -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -arg@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -3532,152 +3281,16 @@ aria-query@^5.0.0: resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.2.tgz#0b8a744295271861e1d933f8feca13f9b70cfdc1" integrity sha512-eigU3vhqSO+Z8BKDnVLN/ompjhf3pYzecKXz8+whRy+9gZu8n1TCGfwzQUUPnqdHl9ax1Hr9031orZ+UOEYr7Q== -aria-query@^5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" - integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== - dependencies: - deep-equal "^2.0.5" - -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - -array-includes@^3.1.5, array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - is-string "^1.0.7" - -array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-string "^1.0.7" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.findlastindex@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" - integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.2.1" - -array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.tosorted@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" - integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" - -arraybuffer.prototype.slice@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" - -ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== - -asynciterator.prototype@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz#8c5df0514936cdd133604dfcc9d3fb93f09b2b62" - integrity sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg== - dependencies: - has-symbols "^1.0.3" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -autoprefixer@^10.4.13: - version "10.4.14" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" - integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== - dependencies: - browserslist "^4.21.5" - caniuse-lite "^1.0.30001464" - fraction.js "^4.2.0" - normalize-range "^0.1.2" - picocolors "^1.0.0" - postcss-value-parser "^4.2.0" - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -axe-core@^4.6.2: - version "4.7.2" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.2.tgz#040a7342b20765cb18bb50b628394c21bccc17a0" - integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g== - axios@^1.6.1: version "1.7.4" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" @@ -3687,13 +3300,6 @@ axios@^1.6.1: form-data "^4.0.0" proxy-from-env "^1.1.0" -axobject-query@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.1.1.tgz#3b6e5c6d4e43ca7ba51c5babf99d22a9c68485e1" - integrity sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg== - dependencies: - deep-equal "^2.0.5" - babel-jest@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" @@ -3897,21 +3503,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -big-integer@^1.6.44: - version "1.6.51" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" - integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -3921,13 +3512,6 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -bplist-parser@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" - integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== - dependencies: - big-integer "^1.6.44" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3943,7 +3527,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: +braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -3965,15 +3549,15 @@ browserslist@^4.21.3, browserslist@^4.21.5: node-releases "^2.0.12" update-browserslist-db "^1.0.11" -browserslist@^4.22.2: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.23.1: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" bs-logger@0.x: version "0.2.6" @@ -4007,21 +3591,7 @@ builtin-modules@^3.3.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== -bundle-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" - integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== - dependencies: - run-applescript "^5.0.0" - -busboy@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - -call-bind@^1.0.0, call-bind@^1.0.2: +call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== @@ -4029,25 +3599,11 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-bind@^1.0.4, call-bind@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" - integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== - dependencies: - function-bind "^1.1.2" - get-intrinsic "^1.2.1" - set-function-length "^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== -camelcase-css@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" - integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -4058,15 +3614,15 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001489: +caniuse-lite@^1.0.30001489: version "1.0.30001581" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz" integrity sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ== -caniuse-lite@^1.0.30001587: - version "1.0.30001620" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz#78bb6f35b8fe315b96b8590597094145d0b146b4" - integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== +caniuse-lite@^1.0.30001663: + version "1.0.30001664" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz#d588d75c9682d3301956b05a3749652a80677df4" + integrity sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g== chalk@4, chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" @@ -4090,21 +3646,6 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chokidar@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - ci-info@^3.2.0: version "3.4.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.4.0.tgz#b28484fd436cbc267900364f096c9dc185efb251" @@ -4134,11 +3675,6 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== -client-only@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" - integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -4180,11 +3716,6 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@^1.1.0, clsx@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -4231,11 +3762,6 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -4294,11 +3820,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - cssom@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" @@ -4328,11 +3849,6 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== -damerau-levenshtein@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" - integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== - data-urls@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" @@ -4365,13 +3881,6 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, d dependencies: ms "2.1.2" -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -4392,30 +3901,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== -deep-equal@^2.0.5: - version "2.2.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.1.tgz#c72ab22f3a7d3503a4ca87dde976fe9978816739" - integrity sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - es-get-iterator "^1.1.3" - get-intrinsic "^1.2.0" - is-arguments "^1.1.1" - is-array-buffer "^3.0.2" - is-date-object "^1.0.5" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - isarray "^2.0.5" - object-is "^1.1.5" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.0" - side-channel "^1.0.4" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" @@ -4426,24 +3911,6 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -default-browser-id@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" - integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== - dependencies: - bplist-parser "^0.2.0" - untildify "^4.0.0" - -default-browser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" - integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== - dependencies: - bundle-name "^3.0.0" - default-browser-id "^3.0.0" - execa "^7.1.1" - titleize "^3.0.0" - defaults@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" @@ -4451,28 +3918,6 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-data-property@^1.0.1, define-data-property@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" - integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== - dependencies: - get-intrinsic "^1.2.1" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - -define-lazy-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" - integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== - -define-properties@^1.1.3, define-properties@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - define-properties@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" @@ -4481,15 +3926,6 @@ define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -4500,11 +3936,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -didyoumean@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" - integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== - diff-sequences@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" @@ -4544,18 +3975,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -dlv@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" - integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -4592,10 +4011,10 @@ electron-to-chromium@^1.4.411: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.418.tgz#9092aca12db25acf02a2ddf9de59f0e4363c9928" integrity sha512-1KnpDTS9onwAfMzW50LcpNtyOkMyjd/OLoD2Kx/DDITZqgNYixY71XNszPHNxyQQ/Brh+FDcUnf4BaM041sdWg== -electron-to-chromium@^1.4.668: - version "1.4.774" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.774.tgz#1017d1758aaeeefe5423aa9d67b4b1e5d1d0a856" - integrity sha512-132O1XCd7zcTkzS3FgkAzKmnBuNJjK8WjcTtNuoylj7MYbqw5eXehjQ5OK91g0zm7OTKIPeaAG4CPoRfD9M1Mg== +electron-to-chromium@^1.5.28: + version "1.5.29" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz#aa592a3caa95d07cc26a66563accf99fa573a1ee" + integrity sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw== emittery@^0.10.2: version "0.10.2" @@ -4617,19 +4036,6 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -enhanced-resolve@^5.12.0: - version "5.14.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz#de684b6803724477a4af5d74ccae5de52c25f6b3" - integrity sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - entities@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" @@ -4642,151 +4048,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" - integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== - dependencies: - array-buffer-byte-length "^1.0.0" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.2.0" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.10" - is-weakref "^1.0.2" - object-inspect "^1.12.3" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" - -es-abstract@^1.22.1: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.12" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" - -es-get-iterator@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" - integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - is-arguments "^1.1.1" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.7" - isarray "^2.0.5" - stop-iteration-iterator "^1.0.0" - -es-iterator-helpers@^1.0.12: - version "1.0.15" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" - integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== - dependencies: - asynciterator.prototype "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.1" - es-abstract "^1.22.1" - es-set-tostringtag "^2.0.1" - function-bind "^1.1.1" - get-intrinsic "^1.2.1" - globalthis "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - internal-slot "^1.0.5" - iterator.prototype "^1.1.2" - safe-array-concat "^1.0.1" - -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== - dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" - -es-shim-unscopables@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== - dependencies: - has "^1.0.3" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - es5-ext@0.8.x: version "0.8.2" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.8.2.tgz#aba8d9e1943a895ac96837a62a39b3f55ecd94ab" @@ -4798,9 +4059,9 @@ escalade@^3.1.1: integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escalade@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^1.0.5: version "1.0.5" @@ -4829,133 +4090,7 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-next@^13.5.6: - version "13.5.6" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.5.6.tgz#3a5a6222d5cb32256760ad68ab8e976e866a08c8" - integrity sha512-o8pQsUHTo9aHqJ2YiZDym5gQAMRf7O2HndHo/JZeY7TDD+W4hk6Ma8Vw54RHiBeb7OWWO5dPirQB+Is/aVQ7Kg== - dependencies: - "@next/eslint-plugin-next" "13.5.6" - "@rushstack/eslint-patch" "^1.3.3" - "@typescript-eslint/parser" "^5.4.2 || ^6.0.0" - eslint-import-resolver-node "^0.3.6" - eslint-import-resolver-typescript "^3.5.2" - eslint-plugin-import "^2.28.1" - eslint-plugin-jsx-a11y "^6.7.1" - eslint-plugin-react "^7.33.2" - eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" - -eslint-import-resolver-node@^0.3.6: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== - dependencies: - debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" - -eslint-import-resolver-node@^0.3.9: - version "0.3.9" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== - dependencies: - debug "^3.2.7" - is-core-module "^2.13.0" - resolve "^1.22.4" - -eslint-import-resolver-typescript@^3.5.2: - version "3.5.5" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz#0a9034ae7ed94b254a360fbea89187b60ea7456d" - integrity sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw== - dependencies: - debug "^4.3.4" - enhanced-resolve "^5.12.0" - eslint-module-utils "^2.7.4" - get-tsconfig "^4.5.0" - globby "^13.1.3" - is-core-module "^2.11.0" - is-glob "^4.0.3" - synckit "^0.8.5" - -eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== - dependencies: - debug "^3.2.7" - -eslint-plugin-import@^2.28.1: - version "2.29.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" - integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== - dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" - array.prototype.flat "^1.3.2" - array.prototype.flatmap "^1.3.2" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" - semver "^6.3.1" - tsconfig-paths "^3.14.2" - -eslint-plugin-jsx-a11y@^6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz#fca5e02d115f48c9a597a6894d5bcec2f7a76976" - integrity sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA== - dependencies: - "@babel/runtime" "^7.20.7" - aria-query "^5.1.3" - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - ast-types-flow "^0.0.7" - axe-core "^4.6.2" - axobject-query "^3.1.1" - damerau-levenshtein "^1.0.8" - emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.3.3" - language-tags "=1.0.5" - minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - semver "^6.3.0" - -"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": - version "4.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" - integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== - -eslint-plugin-react@^7.33.2: - version "7.33.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz#69ee09443ffc583927eafe86ffebb470ee737608" - integrity sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw== - dependencies: - array-includes "^3.1.6" - array.prototype.flatmap "^1.3.1" - array.prototype.tosorted "^1.1.1" - doctrine "^2.1.0" - es-iterator-helpers "^1.0.12" - estraverse "^5.3.0" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.1.2" - object.entries "^1.1.6" - object.fromentries "^2.0.6" - object.hasown "^1.1.2" - object.values "^1.1.6" - prop-types "^15.8.1" - resolve "^2.0.0-next.4" - semver "^6.3.1" - string.prototype.matchall "^4.0.8" - -eslint-scope@^7.1.1, eslint-scope@^7.2.2: +eslint-scope@^7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== @@ -4963,26 +4098,6 @@ eslint-scope@^7.1.1, eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-scope@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" - integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - eslint-visitor-keys@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" @@ -4998,51 +4113,6 @@ eslint-visitor-keys@^3.4.3: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@8.27.0: - version "8.27.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.27.0.tgz#d547e2f7239994ad1faa4bb5d84e5d809db7cf64" - integrity sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ== - dependencies: - "@eslint/eslintrc" "^1.3.3" - "@humanwhocodes/config-array" "^0.11.6" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.4.0" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.15.0" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-sdsl "^4.1.4" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - eslint@8.57.0: version "8.57.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" @@ -5087,27 +4157,28 @@ eslint@8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -eslint@^8.28.0: - version "8.41.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.41.0.tgz#3062ca73363b4714b16dbc1e60f035e6134b6f1c" - integrity sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q== +eslint@^8.57.1: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.0.3" - "@eslint/js" "8.41.0" - "@humanwhocodes/config-array" "^0.11.8" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.1" - espree "^9.5.2" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -5117,7 +4188,6 @@ eslint@^8.28.0: globals "^13.19.0" graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" @@ -5127,12 +4197,11 @@ eslint@^8.28.0: lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.4.0, espree@^9.6.0, espree@^9.6.1: +espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -5141,21 +4210,12 @@ espree@^9.4.0, espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -espree@^9.5.2: - version "9.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" - integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== - dependencies: - acorn "^8.8.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0, esquery@^1.4.2: +esquery@^1.4.2: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -5169,7 +4229,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -5199,21 +4259,6 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" - integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -5257,7 +4302,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.9: +fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== @@ -5321,10 +4366,10 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fbt@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fbt/-/fbt-1.0.0.tgz#1a7c077ee06675e554061160443ed454933a1b4a" - integrity sha512-0LORP21IrBntxDEJOf5Kq4Napf/nsH18EwdMl1AO0clilKjiXBoQUVVY8V2IEgQVT92wBxPtpQfhfC3/EM8QdQ== +fbt@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbt/-/fbt-1.0.2.tgz#96dd326546a16ed50398c4321b08f7ea2da22473" + integrity sha512-vWIasrcX34OW2EWohjrAQM0jpJBH2FjqxW9XrQd38xhtBVXWaks34ePWBSHO3QEShmirRx6kwJNZJrofsHjvlw== dependencies: invariant "^2.2.4" @@ -5405,13 +4450,6 @@ follow-redirects@^1.15.6: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - foreground-child@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" @@ -5429,11 +4467,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== - fs-extra@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" @@ -5448,12 +4481,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fs@^0.0.1-security: - version "0.0.1-security" - resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== - -fsevents@2.3.2, fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -5463,36 +4491,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.2, functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -5512,52 +4510,17 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" -get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - -get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" - integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== - dependencies: - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-stream@^6.0.0, get-stream@^6.0.1: +get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-tsconfig@^4.5.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.6.0.tgz#e977690993a42f3e320e932427502a40f7af6d05" - integrity sha512-lgbo68hHTQnFddybKbbs/RDRJnJT5YyGy2kQzVwbq+g67X73i+5MVTval34QxGkOe9X5Ujf1UYpCaphLyltjEg== - dependencies: - resolve-pkg-maps "^1.0.0" - -glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -5571,35 +4534,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^10.3.10: version "10.3.10" resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" @@ -5639,13 +4573,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.15.0: - version "13.23.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" - integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== - dependencies: - type-fest "^0.20.2" - globals@^13.19.0: version "13.20.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" @@ -5653,13 +4580,6 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -5672,30 +4592,7 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^13.1.3: - version "13.1.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.4.tgz#2f91c116066bcec152465ba36e5caa4a13c01317" - integrity sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g== - dependencies: - dir-glob "^3.0.1" - fast-glob "^3.2.11" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^4.0.0" - -goober@^2.0.33: - version "2.1.13" - resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.13.tgz#e3c06d5578486212a76c9eba860cbc3232ff6d7c" - integrity sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ== - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -5705,21 +4602,11 @@ graceful-fs@^4.2.9: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== - graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -5737,23 +4624,11 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbols@^1.0.2, has-symbols@^1.0.3: +has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -5761,27 +4636,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hasown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" - integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== - dependencies: - function-bind "^1.1.2" - "heap@>= 0.2.0": version "0.2.7" resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== -hermes-eslint@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.14.0.tgz#d56426b0931a7ced99d08b4b6a06f798064b13ba" - integrity sha512-ORk7znDabvALzTbI3QRIQefCkxF1ukDm3dVut3e+cVmwdtsTC71BJetSvdh1jtgK10czwck1QiPZOVOVolhiqQ== - dependencies: - esrecurse "^4.3.0" - hermes-estree "0.14.0" - hermes-parser "0.14.0" - hermes-eslint@^0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.17.1.tgz#e5e43091082dc53a060e0b002324e68943104b71" @@ -5791,11 +4650,6 @@ hermes-eslint@^0.17.1: hermes-estree "0.17.1" hermes-parser "0.17.1" -hermes-estree@0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.14.0.tgz#c663eea1400980802283338a09d0087c448729e7" - integrity sha512-L6M67+0/eSEbt6Ha2XOBFXL++7MR34EOJMgm+j7YCaI4L/jZqrVAg6zYQKzbs1ZCFDLvEQpOgLlapTX4gpFriA== - hermes-estree@0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.15.1.tgz#d06d4ddf87e91857b0130a083a9d7696d7aec61f" @@ -5816,23 +4670,11 @@ hermes-estree@0.20.1: resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.20.1.tgz#0b9a544cf883a779a8e1444b915fa365bef7f72d" integrity sha512-SQpZK4BzR48kuOg0v4pb3EAGNclzIlqMj3Opu/mu7bbAoFw6oig6cEt/RAi0zTFW/iW6Iz9X9ggGuZTAZ/yZHg== -hermes-estree@0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.22.0.tgz#38559502b119f728901d2cfe2ef422f277802a1d" - integrity sha512-FLBt5X9OfA8BERUdc6aZS36Xz3rRuB0Y/mfocSADWEJfomc1xfene33GdyAmtTkKTBXTN/EgAy+rjTKkkZJHlw== - hermes-estree@0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.23.0.tgz#89c5419877b9d6bce4bb616821f496f5c5daddbc" integrity sha512-Rkp0PNLGpORw4ktsttkVbpYJbrYKS3hAnkxu8D9nvQi6LvSbuPa+tYw/t2u3Gjc35lYd/k95YkjqyTcN4zspag== -hermes-parser@0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.14.0.tgz#edb2e7172fce996d2c8bbba250d140b70cc1aaaf" - integrity sha512-pt+8uRiJhVlErY3fiXB3gKhZ72RxM6E1xRMpvfZ5n6Z5TQKQQXKorgRCRzoe02mmvLKBJFP5nPDGv75MWAgCTw== - dependencies: - hermes-estree "0.14.0" - hermes-parser@0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.15.1.tgz#f02587be85228b22841d50f6839ae42a308e5100" @@ -5868,13 +4710,6 @@ hermes-parser@^0.20.1: dependencies: hermes-estree "0.20.1" -hermes-parser@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.22.0.tgz#fc8e0e6c7bfa8db85b04c9f9544a102c4fcb4040" - integrity sha512-gn5RfZiEXCsIWsFGsKiykekktUoh0PdFWYocXsUdZIyWSckT6UIyPcyyUIPSR3kpnELWeK3n3ztAse7Mat6PSA== - dependencies: - hermes-estree "0.22.0" - html-encoding-sniffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" @@ -5909,11 +4744,6 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== - iconv-lite@0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -5936,7 +4766,12 @@ ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== -import-fresh@^3.0.0, import-fresh@^3.2.1: +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -5970,15 +4805,6 @@ inherits@2, inherits@^2.0.3, inherits@^2.0.4: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== - dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" - side-channel "^1.0.4" - invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -5986,57 +4812,11 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -is-arguments@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - 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== -is-async-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" - integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== - dependencies: - has-tostringtag "^1.0.0" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-builtin-module@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" @@ -6044,11 +4824,6 @@ is-builtin-module@^3.2.1: dependencies: builtin-modules "^3.3.0" -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-core-module@^2.11.0: version "2.12.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" @@ -6056,13 +4831,6 @@ is-core-module@^2.11.0: dependencies: has "^1.0.3" -is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== - dependencies: - hasown "^2.0.0" - is-core-module@^2.9.0: version "2.10.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" @@ -6070,35 +4838,11 @@ is-core-module@^2.9.0: dependencies: has "^1.0.3" -is-date-object@^1.0.1, is-date-object@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-docker@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" - integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-finalizationregistry@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" - integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== - dependencies: - call-bind "^1.0.2" - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -6109,54 +4853,23 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-inside-container@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" - integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== - dependencies: - is-docker "^3.0.0" - is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -is-map@^2.0.1, is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== - is-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -6186,105 +4899,16 @@ is-reference@1.2.1: dependencies: "@types/estree" "*" -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-set@^2.0.1, is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -is-typed-array@^1.1.12: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== - dependencies: - which-typed-array "^1.1.11" - is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -6337,17 +4961,6 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterator.prototype@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" - integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== - dependencies: - define-properties "^1.2.1" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - reflect.getprototypeof "^1.0.4" - set-function-name "^2.0.1" - jackspeak@^2.3.5: version "2.3.6" resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" @@ -7446,11 +6059,6 @@ jest@^29.5.0: import-local "^3.0.2" jest-cli "^29.5.0" -jiti@^1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd" - integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg== - joi@^17.11.0: version "17.13.1" resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.1.tgz#9c7b53dc3b44dd9ae200255cc3b398874918a6ca" @@ -7462,11 +6070,6 @@ joi@^17.11.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" -js-sdsl@^4.1.4: - version "4.4.2" - resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.2.tgz#2e3c031b1f47d3aca8b775532e3ebb0818e7f847" - integrity sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -7583,19 +6186,12 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - json5@^2.1.0, json5@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== -json5@^2.1.2, json5@^2.2.3: +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== @@ -7607,14 +6203,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" - integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== - dependencies: - array-includes "^3.1.5" - object.assign "^4.1.3" - keypress@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.2.1.tgz#1e80454250018dbad4c3fe94497d6e67b6269c77" @@ -7630,18 +6218,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -language-subtag-registry@~0.3.2: - version "0.3.22" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" - integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== - -language-tags@=1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== - dependencies: - language-subtag-registry "~0.3.2" - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -7663,25 +6239,11 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lilconfig@^2.0.5, lilconfig@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== - 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== -loader-utils@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" - integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -7739,7 +6301,7 @@ lodash.omitby@4.6.0: resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791" integrity sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ== -lodash@^4.17.10, lodash@^4.17.21: +lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7752,7 +6314,7 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -7783,11 +6345,6 @@ lz-string@^1.4.4: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== -lz-string@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" - integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== - magic-string@0.30.5: version "0.30.5" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" @@ -7871,11 +6428,6 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== - minimatch@9.0.3, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -7897,62 +6449,28 @@ minimatch@^5.0.1, minimatch@~5.1.2: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.8: +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== - "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": version "7.0.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== -monaco-editor-webpack-plugin@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.1.0.tgz#16f265c2b5dbb5fe08681b6b3b7d00d3c5b2ee97" - integrity sha512-ZjnGINHN963JQkFqjjcBtn1XBtUATDZBMgNQhDQwd78w2ukRhFXAPNgWuacaQiDZsUr4h1rWv5Mv6eriKuOSzA== - dependencies: - loader-utils "^2.0.2" - -monaco-editor@^0.34.1: - version "0.34.1" - resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87" - integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -mz@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - -nanoid@^3.3.6: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== - -nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - native-or-another@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/native-or-another/-/native-or-another-2.0.0.tgz#17a567f92beea9cd71acff96a7681a735eca3bff" @@ -7970,29 +6488,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@^13.5.6: - version "13.5.6" - resolved "https://registry.yarnpkg.com/next/-/next-13.5.6.tgz#e964b5853272236c37ce0dd2c68302973cf010b1" - integrity sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw== - dependencies: - "@next/env" "13.5.6" - "@swc/helpers" "0.5.2" - busboy "1.6.0" - caniuse-lite "^1.0.30001406" - postcss "8.4.31" - styled-jsx "5.1.1" - watchpack "2.4.0" - optionalDependencies: - "@next/swc-darwin-arm64" "13.5.6" - "@next/swc-darwin-x64" "13.5.6" - "@next/swc-linux-arm64-gnu" "13.5.6" - "@next/swc-linux-arm64-musl" "13.5.6" - "@next/swc-linux-x64-gnu" "13.5.6" - "@next/swc-linux-x64-musl" "13.5.6" - "@next/swc-win32-arm64-msvc" "13.5.6" - "@next/swc-win32-ia32-msvc" "13.5.6" - "@next/swc-win32-x64-msvc" "13.5.6" - node-addon-api@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -8013,29 +6508,16 @@ node-releases@^2.0.12: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== -normalize-path@^3.0.0, normalize-path@~3.0.0: +normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== - -notistack@^3.0.0-alpha.7: - version "3.0.1" - resolved "https://registry.yarnpkg.com/notistack/-/notistack-3.0.1.tgz#daf59888ab7e2c30a1fa8f71f9cba2978773236e" - integrity sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA== - dependencies: - clsx "^1.1.0" - goober "^2.0.33" - npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -8043,13 +6525,6 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== - dependencies: - path-key "^4.0.0" - nullthrows@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" @@ -8065,40 +6540,17 @@ nwsapi@^2.2.4: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== -object-assign@^4.0.1, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-hash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" - integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== - -object-inspect@^1.12.3, object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - -object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== - -object-is@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.0, object.assign@^4.1.3, object.assign@^4.1.4: +object.assign@^4.1.0: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== @@ -8108,69 +6560,6 @@ object.assign@^4.1.0, object.assign@^4.1.3, object.assign@^4.1.4: has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" - integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.fromentries@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -object.groupby@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" - integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - -object.hasown@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" - integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== - dependencies: - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.values@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -8185,23 +6574,6 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - -open@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" - integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== - dependencies: - default-browser "^4.0.0" - define-lazy-prop "^3.0.0" - is-inside-container "^1.0.0" - is-wsl "^2.2.0" - optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -8214,18 +6586,6 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -8344,11 +6704,6 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -8373,26 +6728,21 @@ picocolors@^1.0.0: integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== - pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: +pirates@^4.0.4, pirates@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -8411,82 +6761,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.42.1: - version "1.42.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.42.1.tgz#13c150b93c940a3280ab1d3fbc945bc855c9459e" - integrity sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA== - -playwright@1.42.1: - version "1.42.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.42.1.tgz#79c828b51fe3830211137550542426111dc8239f" - integrity sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg== - dependencies: - playwright-core "1.42.1" - optionalDependencies: - fsevents "2.3.2" - -postcss-import@^15.1.0: - version "15.1.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70" - integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== - dependencies: - postcss-value-parser "^4.0.0" - read-cache "^1.0.0" - resolve "^1.1.7" - -postcss-js@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2" - integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== - dependencies: - camelcase-css "^2.0.1" - -postcss-load-config@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd" - integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA== - dependencies: - lilconfig "^2.0.5" - yaml "^2.1.1" - -postcss-nested@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.1.tgz#f83dc9846ca16d2f4fa864f16e9d9f7d0961662c" - integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== - dependencies: - postcss-selector-parser "^6.0.11" - -postcss-selector-parser@^6.0.11: - version "6.0.13" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" - integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - -postcss@8.4.31, postcss@^8.4.23: - version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" - integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== - dependencies: - nanoid "^3.3.6" - picocolors "^1.0.0" - source-map-js "^1.0.2" - -postcss@^8.4.31: - version "8.4.38" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" - integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== - dependencies: - nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.2.0" - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -8549,7 +6823,7 @@ pretty-format@^29.0.0, pretty-format@^29.0.3: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-format@^29.3.1, pretty-format@^29.5.0: +pretty-format@^29.5.0: version "29.5.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== @@ -8574,15 +6848,6 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -8625,19 +6890,6 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -re-resizable@^6.9.16: - version "6.9.16" - resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.16.tgz#d040a3ba9ccb25a3cc85b7622d4eafdee48cf2c2" - integrity sha512-D9+ofwgPQRC6PL6cwavCZO9MUR8TKKxV1nHjbutSdNaFHK9v5k8m6DcESMXrw1+mRJn7fBHJRhZpa7EQ1ZWEEA== - -react-dom@18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" - integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.0" - react-dom@19.0.0-beta-b498834eab-20240506: version "19.0.0-beta-b498834eab-20240506" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-b498834eab-20240506.tgz#1860706b1b5b68850fad0f44d08ae43311fe1171" @@ -8645,30 +6897,16 @@ react-dom@19.0.0-beta-b498834eab-20240506: dependencies: scheduler "0.25.0-beta-b498834eab-20240506" -react-is@19.0.0-beta-b498834eab-20240506, react-is@^16.13.1, react-is@^16.8.4, react-is@^17.0.1, react-is@^18.0.0: +react-is@19.0.0-beta-b498834eab-20240506, react-is@^16.8.4, react-is@^17.0.1, react-is@^18.0.0: version "19.0.0-beta-b498834eab-20240506" resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.0.0-beta-b498834eab-20240506.tgz#772f7d3ff4997997730f54cad28282214b487294" integrity sha512-n4bHxssA5Y0y1Vx4P0aBybxp0VviakagM9wgP961sVCj2hndZqb/NcVEmIkwxAL2ha4kv/l1zaUiIH+4fSZJkg== -react@18.2.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" - integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== - dependencies: - loose-envify "^1.1.0" - react@19.0.0-beta-b498834eab-20240506: version "19.0.0-beta-b498834eab-20240506" resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-beta-b498834eab-20240506.tgz#36a99a1160ca055725a092630641c2dd77b62f33" integrity sha512-mK8kVx7e0M6bVvjc+G+48Oo4TJJ1Y84JUrs60MbIw8WoqqHmG9qPFz3IwhXqzVtugqBMog5UA4KEZW+nHxewkw== -read-cache@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" - integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== - dependencies: - pify "^2.3.0" - readable-stream@^3.4.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" @@ -8678,30 +6916,11 @@ readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - readline@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" integrity sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg== -reflect.getprototypeof@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" - integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - globalthis "^1.0.3" - which-builtin-type "^1.1.3" - regenerate-unicode-properties@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" @@ -8731,29 +6950,6 @@ regenerator-transform@^0.15.1: dependencies: "@babel/runtime" "^7.8.4" -regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - functions-have-names "^1.2.3" - -regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - regexpu-core@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" @@ -8805,11 +7001,6 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-pkg-maps@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" - integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== - resolve.exports@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" @@ -8820,7 +7011,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.1, resolve@^1.22.2: +resolve@^1.14.2, resolve@^1.22.1: version "1.22.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== @@ -8838,24 +7029,6 @@ resolve@^1.20.0, resolve@^1.3.2: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -8926,13 +7099,6 @@ rrweb-cssom@^0.6.0: resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== -run-applescript@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" - integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== - dependencies: - execa "^5.0.0" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -8947,16 +7113,6 @@ rxjs@^7.0.0, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" - integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - isarray "^2.0.5" - safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -8967,15 +7123,6 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -8993,13 +7140,6 @@ scheduler@0.25.0-beta-b498834eab-20240506: resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-b498834eab-20240506.tgz#ddbdfe82bdf7a4dda551974c54b9b68e75cb9ba1" integrity sha512-fw52C9FJ90xSu8R2vRfYX8WiI3sz4zo/ya98DRdRqkkgek6WYofI7AJRM5ZZxFtVKuJZOUjV+4uoVK9Al1XadA== -scheduler@^0.23.0: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - semver@7.x, semver@^7.3.5: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -9029,6 +7169,11 @@ semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-javascript@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" @@ -9041,25 +7186,6 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== -set-function-length@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" - integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== - dependencies: - define-data-property "^1.1.1" - get-intrinsic "^1.2.1" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - -set-function-name@^2.0.0, set-function-name@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== - dependencies: - define-data-property "^1.0.1" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -9084,15 +7210,6 @@ shell-quote@^1.7.3: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -9113,26 +7230,11 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== - smob@^1.0.0: version "1.5.0" resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -9181,23 +7283,6 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -state-local@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5" - integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w== - -stop-iteration-iterator@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" - integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== - dependencies: - internal-slot "^1.0.4" - -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -9233,74 +7318,6 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.matchall@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" - integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" - -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -9329,11 +7346,6 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - strip-bom@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" @@ -9344,36 +7356,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -styled-jsx@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" - integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== - dependencies: - client-only "0.0.1" - -sucrase@^3.32.0: - version "3.32.0" - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.32.0.tgz#c4a95e0f1e18b6847127258a75cf360bc568d4a7" - integrity sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.2" - commander "^4.0.0" - glob "7.1.6" - lines-and-columns "^1.1.6" - mz "^2.7.0" - pirates "^4.0.1" - ts-interface-checker "^0.1.9" - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -9413,48 +7400,6 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -synckit@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" - integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== - dependencies: - "@pkgr/utils" "^2.3.1" - tslib "^2.5.0" - -tailwindcss@^3.2.4: - version "3.3.2" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.2.tgz#2f9e35d715fdf0bbf674d90147a0684d7054a2d3" - integrity sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w== - dependencies: - "@alloc/quick-lru" "^5.2.0" - arg "^5.0.2" - chokidar "^3.5.3" - didyoumean "^1.2.2" - dlv "^1.1.3" - fast-glob "^3.2.12" - glob-parent "^6.0.2" - is-glob "^4.0.3" - jiti "^1.18.2" - lilconfig "^2.1.0" - micromatch "^4.0.5" - normalize-path "^3.0.0" - object-hash "^3.0.0" - picocolors "^1.0.0" - postcss "^8.4.23" - postcss-import "^15.1.0" - postcss-js "^4.0.1" - postcss-load-config "^4.0.1" - postcss-nested "^6.0.1" - postcss-selector-parser "^6.0.11" - postcss-value-parser "^4.2.0" - resolve "^1.22.2" - sucrase "^3.32.0" - -tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -9487,25 +7432,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - -titleize@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" - integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== - tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -9562,10 +7488,10 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== -ts-interface-checker@^0.1.9: - version "0.1.13" - resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" - integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-jest@^28.0.7: version "28.0.8" @@ -9614,17 +7540,7 @@ ts-node@^10.9.2: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsconfig-paths@^3.14.2: - version "3.14.2" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0: +tslib@^2.1.0: version "2.5.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.2.tgz#1b6f07185c881557b0ffa84b111a0106989e8338" integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA== @@ -9658,60 +7574,11 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" - -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - typescript@^5.4.3: version "5.4.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" @@ -9745,11 +7612,6 @@ universalify@^0.2.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - update-browserslist-db@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" @@ -9758,10 +7620,10 @@ update-browserslist-db@^1.0.11: escalade "^3.1.1" picocolors "^1.0.0" -update-browserslist-db@^1.0.13: - version "1.0.16" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356" - integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== +update-browserslist-db@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" + integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== dependencies: escalade "^3.1.2" picocolors "^1.0.1" @@ -9781,7 +7643,7 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -util-deprecate@^1.0.1, util-deprecate@^1.0.2: +util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== @@ -9839,14 +7701,6 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -watchpack@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -9887,73 +7741,11 @@ whatwg-url@^12.0.0, whatwg-url@^12.0.1: tr46 "^4.1.1" webidl-conversions "^7.0.0" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-builtin-type@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" - integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== - dependencies: - function.prototype.name "^1.1.5" - has-tostringtag "^1.0.0" - is-async-function "^2.0.0" - is-date-object "^1.0.5" - is-finalizationregistry "^1.0.2" - is-generator-function "^1.0.10" - is-regex "^1.1.4" - is-weakref "^1.0.2" - isarray "^2.0.5" - which-boxed-primitive "^1.0.2" - which-collection "^1.0.1" - which-typed-array "^1.1.9" - -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== - dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== -which-typed-array@^1.1.11, which-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" - integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.4" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -9961,7 +7753,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -word-wrap@^1.2.3, word-wrap@~1.2.3: +word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== @@ -10055,11 +7847,6 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" From 2d16326d9a3f45260aa80bcae78745ab2f199138 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Mon, 30 Sep 2024 17:07:54 +0100 Subject: [PATCH 215/426] fix[scripts/devtools/publish-release]: parse version list instead of handling 404 (#31087) Discovered yesterday while was publishing a new release. NPM `10.x.x` changed the text for 404 errors, so this check was failing. Instead of handling 404 as a signal, I think its better to just parse the whole list of versions and check if the new one is already there. --- scripts/devtools/publish-release.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/scripts/devtools/publish-release.js b/scripts/devtools/publish-release.js index 495fddefc2cd6..6a2ab4f79d2ef 100755 --- a/scripts/devtools/publish-release.js +++ b/scripts/devtools/publish-release.js @@ -82,18 +82,13 @@ async function publishToNPM() { // If so we might be resuming from a previous run. // We could infer this by comparing the build-info.json, // But for now the easiest way is just to ask if this is expected. - const info = await execRead(`npm view ${npmPackage}@${version}`) - // Early versions of npm view gives empty response, but newer versions give 404 error. - // Catch the error to keep it consistent. - .catch(childProcessError => { - if (childProcessError.stderr.startsWith('npm ERR! code E404')) { - return null; - } - - throw childProcessError; - }); + const versionListJSON = await execRead( + `npm view ${npmPackage} versions --json` + ); + const versionList = JSON.parse(versionListJSON); + const versionIsAlreadyPublished = versionList.includes(version); - if (info) { + if (versionIsAlreadyPublished) { console.log(''); console.log( `${npmPackage} version ${chalk.bold( From 943e45e910d1a125f2be431c2b66f22a035ea0c9 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:19 -0400 Subject: [PATCH 216/426] [compiler][test fixtures] Fork more fixtures for hir-rewrite Followup from #30894 , not sure how these got missed. Note that this PR just copies the fixtures without adding `@enablePropagateDepsInHIR`. #31032 follows and actually enables the HIR-version of propagateScopeDeps to run. I split this out into two PRs to make snapshot differences easier to review, but also happy to merge Fixtures found from locally setting snap test runner to default to `enablePropagateDepsInHIR: 'enabled_baseline'` and forking fixtures files with different output. ghstack-source-id: 7d7cf41aa923d83ad49f89079171b0411923ce6b Pull Request resolved: https://github.com/facebook/react/pull/31030 --- .../conditional-break-labeled.expect.md | 65 ++++++ .../conditional-break-labeled.js | 21 ++ .../conditional-early-return.expect.md | 197 ++++++++++++++++++ .../conditional-early-return.js | 58 ++++++ .../conditional-on-mutable.expect.md | 88 ++++++++ .../conditional-on-mutable.js | 26 +++ ...rly-return-within-reactive-scope.expect.md | 89 ++++++++ ...sted-early-return-within-reactive-scope.js | 21 ++ ...rly-return-within-reactive-scope.expect.md | 112 ++++++++++ .../early-return-within-reactive-scope.js | 33 +++ ...-optional-call-chain-in-optional.expect.md | 34 +++ ...or.todo-optional-call-chain-in-optional.ts | 13 ++ .../iife-return-modified-later-phi.expect.md | 57 +++++ .../iife-return-modified-later-phi.js | 16 ++ ...consequent-alternate-both-return.expect.md | 66 ++++++ ...ted-in-consequent-alternate-both-return.js | 17 ++ ...rly-return-within-reactive-scope.expect.md | 80 +++++++ ...tial-early-return-within-reactive-scope.js | 20 ++ ...ence-array-push-consecutive-phis.expect.md | 110 ++++++++++ ...e-inference-array-push-consecutive-phis.js | 37 ++++ .../phi-type-inference-array-push.expect.md | 83 ++++++++ .../phi-type-inference-array-push.js | 26 +++ ...hi-type-inference-property-store.expect.md | 72 +++++++ .../phi-type-inference-property-store.js | 22 ++ ...properties-inside-optional-chain.expect.md | 31 +++ ...tional-properties-inside-optional-chain.js | 3 + ...ming-unconditional-with-mutation.expect.md | 79 +++++++ ...sa-renaming-unconditional-with-mutation.js | 27 +++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 29 files changed, 1504 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md new file mode 100644 index 0000000000000..76648c251a101 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md @@ -0,0 +1,65 @@ + +## Input + +```javascript +/** + * props.b *does* influence `a` + */ +function Component(props) { + const a = []; + a.push(props.a); + label: { + if (props.b) { + break label; + } + a.push(props.c); + } + a.push(props.d); + return a; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ['TodoAdd'], + isComponent: 'TodoAdd', +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; /** + * props.b *does* influence `a` + */ +function Component(props) { + const $ = _c(2); + let a; + if ($[0] !== props) { + a = []; + a.push(props.a); + bb0: { + if (props.b) { + break bb0; + } + + a.push(props.c); + } + + a.push(props.d); + $[0] = props; + $[1] = a; + } else { + a = $[1]; + } + return a; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ["TodoAdd"], + isComponent: "TodoAdd", +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js new file mode 100644 index 0000000000000..ccf983189cf71 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js @@ -0,0 +1,21 @@ +/** + * props.b *does* influence `a` + */ +function Component(props) { + const a = []; + a.push(props.a); + label: { + if (props.b) { + break label; + } + a.push(props.c); + } + a.push(props.d); + return a; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: ['TodoAdd'], + isComponent: 'TodoAdd', +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md new file mode 100644 index 0000000000000..82537902bfa19 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md @@ -0,0 +1,197 @@ + +## Input + +```javascript +/** + * props.b does *not* influence `a` + */ +function ComponentA(props) { + const a_DEBUG = []; + a_DEBUG.push(props.a); + if (props.b) { + return null; + } + a_DEBUG.push(props.d); + return a_DEBUG; +} + +/** + * props.b *does* influence `a` + */ +function ComponentB(props) { + const a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + } + a.push(props.d); + return a; +} + +/** + * props.b *does* influence `a`, but only in a way that is never observable + */ +function ComponentC(props) { + const a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + return null; + } + a.push(props.d); + return a; +} + +/** + * props.b *does* influence `a` + */ +function ComponentD(props) { + const a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + return a; + } + a.push(props.d); + return a; +} + +export const FIXTURE_ENTRYPOINT = { + fn: ComponentA, + params: [{a: 1, b: false, d: 3}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; /** + * props.b does *not* influence `a` + */ +function ComponentA(props) { + const $ = _c(3); + let a_DEBUG; + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + a_DEBUG = []; + a_DEBUG.push(props.a); + if (props.b) { + t0 = null; + break bb0; + } + + a_DEBUG.push(props.d); + } + $[0] = props; + $[1] = a_DEBUG; + $[2] = t0; + } else { + a_DEBUG = $[1]; + t0 = $[2]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } + return a_DEBUG; +} + +/** + * props.b *does* influence `a` + */ +function ComponentB(props) { + const $ = _c(2); + let a; + if ($[0] !== props) { + a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + } + + a.push(props.d); + $[0] = props; + $[1] = a; + } else { + a = $[1]; + } + return a; +} + +/** + * props.b *does* influence `a`, but only in a way that is never observable + */ +function ComponentC(props) { + const $ = _c(3); + let a; + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + t0 = null; + break bb0; + } + + a.push(props.d); + } + $[0] = props; + $[1] = a; + $[2] = t0; + } else { + a = $[1]; + t0 = $[2]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } + return a; +} + +/** + * props.b *does* influence `a` + */ +function ComponentD(props) { + const $ = _c(3); + let a; + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + t0 = a; + break bb0; + } + + a.push(props.d); + } + $[0] = props; + $[1] = a; + $[2] = t0; + } else { + a = $[1]; + t0 = $[2]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } + return a; +} + +export const FIXTURE_ENTRYPOINT = { + fn: ComponentA, + params: [{ a: 1, b: false, d: 3 }], +}; + +``` + +### Eval output +(kind: ok) [1,3] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js new file mode 100644 index 0000000000000..e0ed101409252 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js @@ -0,0 +1,58 @@ +/** + * props.b does *not* influence `a` + */ +function ComponentA(props) { + const a_DEBUG = []; + a_DEBUG.push(props.a); + if (props.b) { + return null; + } + a_DEBUG.push(props.d); + return a_DEBUG; +} + +/** + * props.b *does* influence `a` + */ +function ComponentB(props) { + const a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + } + a.push(props.d); + return a; +} + +/** + * props.b *does* influence `a`, but only in a way that is never observable + */ +function ComponentC(props) { + const a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + return null; + } + a.push(props.d); + return a; +} + +/** + * props.b *does* influence `a` + */ +function ComponentD(props) { + const a = []; + a.push(props.a); + if (props.b) { + a.push(props.c); + return a; + } + a.push(props.d); + return a; +} + +export const FIXTURE_ENTRYPOINT = { + fn: ComponentA, + params: [{a: 1, b: false, d: 3}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md new file mode 100644 index 0000000000000..24c565b088d2f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md @@ -0,0 +1,88 @@ + +## Input + +```javascript +function ComponentA(props) { + const a = []; + const b = []; + if (b) { + a.push(props.p0); + } + if (props.p1) { + b.push(props.p2); + } + return ; +} + +function ComponentB(props) { + const a = []; + const b = []; + if (mayMutate(b)) { + a.push(props.p0); + } + if (props.p1) { + b.push(props.p2); + } + return ; +} + +function Foo() {} +function mayMutate() {} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function ComponentA(props) { + const $ = _c(2); + let t0; + if ($[0] !== props) { + const a = []; + const b = []; + if (b) { + a.push(props.p0); + } + if (props.p1) { + b.push(props.p2); + } + + t0 = ; + $[0] = props; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +function ComponentB(props) { + const $ = _c(2); + let t0; + if ($[0] !== props) { + const a = []; + const b = []; + if (mayMutate(b)) { + a.push(props.p0); + } + if (props.p1) { + b.push(props.p2); + } + + t0 = ; + $[0] = props; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +function Foo() {} +function mayMutate() {} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js new file mode 100644 index 0000000000000..0378ab655c1ef --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js @@ -0,0 +1,26 @@ +function ComponentA(props) { + const a = []; + const b = []; + if (b) { + a.push(props.p0); + } + if (props.p1) { + b.push(props.p2); + } + return ; +} + +function ComponentB(props) { + const a = []; + const b = []; + if (mayMutate(b)) { + a.push(props.p0); + } + if (props.p1) { + b.push(props.p2); + } + return ; +} + +function Foo() {} +function mayMutate() {} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md new file mode 100644 index 0000000000000..2d33981f73fd1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md @@ -0,0 +1,89 @@ + +## Input + +```javascript +function Component(props) { + let x = []; + if (props.cond) { + x.push(props.a); + if (props.b) { + const y = [props.b]; + x.push(y); + // oops no memo! + return x; + } + // oops no memo! + return x; + } else { + return foo(); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, a: 42, b: 3.14}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(5); + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + const x = []; + if (props.cond) { + x.push(props.a); + if (props.b) { + let t1; + if ($[2] !== props.b) { + t1 = [props.b]; + $[2] = props.b; + $[3] = t1; + } else { + t1 = $[3]; + } + const y = t1; + x.push(y); + t0 = x; + break bb0; + } + + t0 = x; + break bb0; + } else { + let t1; + if ($[4] === Symbol.for("react.memo_cache_sentinel")) { + t1 = foo(); + $[4] = t1; + } else { + t1 = $[4]; + } + t0 = t1; + break bb0; + } + } + $[0] = props; + $[1] = t0; + } else { + t0 = $[1]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: true, a: 42, b: 3.14 }], +}; + +``` + +### Eval output +(kind: ok) [42,[3.14]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js new file mode 100644 index 0000000000000..53eb06bc591e4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js @@ -0,0 +1,21 @@ +function Component(props) { + let x = []; + if (props.cond) { + x.push(props.a); + if (props.b) { + const y = [props.b]; + x.push(y); + // oops no memo! + return x; + } + // oops no memo! + return x; + } else { + return foo(); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, a: 42, b: 3.14}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md new file mode 100644 index 0000000000000..6c3525e9e77eb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md @@ -0,0 +1,112 @@ + +## Input + +```javascript +import {makeArray} from 'shared-runtime'; + +function Component(props) { + let x = []; + if (props.cond) { + x.push(props.a); + // oops no memo! + return x; + } else { + return makeArray(props.b); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + sequentialRenders: [ + // pattern 1 + {cond: true, a: 42}, + {cond: true, a: 42}, + // pattern 2 + {cond: false, b: 3.14}, + {cond: false, b: 3.14}, + // pattern 1 + {cond: true, a: 42}, + // pattern 2 + {cond: false, b: 3.14}, + // pattern 1 + {cond: true, a: 42}, + // pattern 2 + {cond: false, b: 3.14}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { makeArray } from "shared-runtime"; + +function Component(props) { + const $ = _c(4); + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + const x = []; + if (props.cond) { + x.push(props.a); + t0 = x; + break bb0; + } else { + let t1; + if ($[2] !== props.b) { + t1 = makeArray(props.b); + $[2] = props.b; + $[3] = t1; + } else { + t1 = $[3]; + } + t0 = t1; + break bb0; + } + } + $[0] = props; + $[1] = t0; + } else { + t0 = $[1]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + sequentialRenders: [ + // pattern 1 + { cond: true, a: 42 }, + { cond: true, a: 42 }, + // pattern 2 + { cond: false, b: 3.14 }, + { cond: false, b: 3.14 }, + // pattern 1 + { cond: true, a: 42 }, + // pattern 2 + { cond: false, b: 3.14 }, + // pattern 1 + { cond: true, a: 42 }, + // pattern 2 + { cond: false, b: 3.14 }, + ], +}; + +``` + +### Eval output +(kind: ok) [42] +[42] +[3.14] +[3.14] +[42] +[3.14] +[42] +[3.14] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js new file mode 100644 index 0000000000000..7446d76fb320c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js @@ -0,0 +1,33 @@ +import {makeArray} from 'shared-runtime'; + +function Component(props) { + let x = []; + if (props.cond) { + x.push(props.a); + // oops no memo! + return x; + } else { + return makeArray(props.b); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], + sequentialRenders: [ + // pattern 1 + {cond: true, a: 42}, + {cond: true, a: 42}, + // pattern 2 + {cond: false, b: 3.14}, + {cond: false, b: 3.14}, + // pattern 1 + {cond: true, a: 42}, + // pattern 2 + {cond: false, b: 3.14}, + // pattern 1 + {cond: true, a: 42}, + // pattern 2 + {cond: false, b: 3.14}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md new file mode 100644 index 0000000000000..75c5d61d407f0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md @@ -0,0 +1,34 @@ + +## Input + +```javascript +function useFoo(props: {value: {x: string; y: string} | null}) { + const value = props.value; + return createArray(value?.x, value?.y)?.join(', '); +} + +function createArray(...args: Array): Array { + return args; +} + +export const FIXTURE_ENTRYPONT = { + fn: useFoo, + props: [{value: null}], +}; + +``` + + +## Error + +``` + 1 | function useFoo(props: {value: {x: string; y: string} | null}) { + 2 | const value = props.value; +> 3 | return createArray(value?.x, value?.y)?.join(', '); + | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional test block (3:3) + 4 | } + 5 | + 6 | function createArray(...args: Array): Array { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts new file mode 100644 index 0000000000000..7ee50e0380288 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts @@ -0,0 +1,13 @@ +function useFoo(props: {value: {x: string; y: string} | null}) { + const value = props.value; + return createArray(value?.x, value?.y)?.join(', '); +} + +function createArray(...args: Array): Array { + return args; +} + +export const FIXTURE_ENTRYPONT = { + fn: useFoo, + props: [{value: null}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md new file mode 100644 index 0000000000000..bed1c329f0d10 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md @@ -0,0 +1,57 @@ + +## Input + +```javascript +function Component(props) { + const items = (() => { + if (props.cond) { + return []; + } else { + return null; + } + })(); + items?.push(props.a); + return items; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: {}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(2); + let items; + if ($[0] !== props) { + let t0; + if (props.cond) { + t0 = []; + } else { + t0 = null; + } + items = t0; + + items?.push(props.a); + $[0] = props; + $[1] = items; + } else { + items = $[1]; + } + return items; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: {} }], +}; + +``` + +### Eval output +(kind: ok) null \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js new file mode 100644 index 0000000000000..f4f953d294e6f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js @@ -0,0 +1,16 @@ +function Component(props) { + const items = (() => { + if (props.cond) { + return []; + } else { + return null; + } + })(); + items?.push(props.a); + return items; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{a: {}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md new file mode 100644 index 0000000000000..8a20f9186b447 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md @@ -0,0 +1,66 @@ + +## Input + +```javascript +import {makeObject_Primitives} from 'shared-runtime'; + +function Component(props) { + const object = makeObject_Primitives(); + if (props.cond) { + object.value = 1; + return object; + } else { + object.value = props.value; + return object; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: false, value: [0, 1, 2]}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { makeObject_Primitives } from "shared-runtime"; + +function Component(props) { + const $ = _c(2); + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + const object = makeObject_Primitives(); + if (props.cond) { + object.value = 1; + t0 = object; + break bb0; + } else { + object.value = props.value; + t0 = object; + break bb0; + } + } + $[0] = props; + $[1] = t0; + } else { + t0 = $[1]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: false, value: [0, 1, 2] }], +}; + +``` + +### Eval output +(kind: ok) {"a":0,"b":"value1","c":true,"value":[0,1,2]} \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js new file mode 100644 index 0000000000000..94a142d033708 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js @@ -0,0 +1,17 @@ +import {makeObject_Primitives} from 'shared-runtime'; + +function Component(props) { + const object = makeObject_Primitives(); + if (props.cond) { + object.value = 1; + return object; + } else { + object.value = props.value; + return object; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: false, value: [0, 1, 2]}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md new file mode 100644 index 0000000000000..398161f0c6a24 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md @@ -0,0 +1,80 @@ + +## Input + +```javascript +function Component(props) { + let x = []; + let y = null; + if (props.cond) { + x.push(props.a); + // oops no memo! + return x; + } else { + y = foo(); + if (props.b) { + return; + } + } + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, a: 42}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(4); + let y; + let t0; + if ($[0] !== props) { + t0 = Symbol.for("react.early_return_sentinel"); + bb0: { + const x = []; + if (props.cond) { + x.push(props.a); + t0 = x; + break bb0; + } else { + let t1; + if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + t1 = foo(); + $[3] = t1; + } else { + t1 = $[3]; + } + y = t1; + if (props.b) { + t0 = undefined; + break bb0; + } + } + } + $[0] = props; + $[1] = y; + $[2] = t0; + } else { + y = $[1]; + t0 = $[2]; + } + if (t0 !== Symbol.for("react.early_return_sentinel")) { + return t0; + } + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: true, a: 42 }], +}; + +``` + +### Eval output +(kind: ok) [42] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js new file mode 100644 index 0000000000000..66d68242b8bb6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js @@ -0,0 +1,20 @@ +function Component(props) { + let x = []; + let y = null; + if (props.cond) { + x.push(props.a); + // oops no memo! + return x; + } else { + y = foo(); + if (props.b) { + return; + } + } + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, a: 42}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md new file mode 100644 index 0000000000000..f17bcc92cb7ce --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md @@ -0,0 +1,110 @@ + +## Input + +```javascript +import {makeArray} from 'shared-runtime'; + +function Component(props) { + const x = {}; + let y; + if (props.cond) { + if (props.cond2) { + y = [props.value]; + } else { + y = [props.value2]; + } + } else { + y = []; + } + // This should be inferred as ` y` s.t. `x` can still + // be independently memoized. *But* this also must properly + // extend the mutable range of the array literals in the + // if/else branches + y.push(x); + + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, cond2: true, value: 42}], + sequentialRenders: [ + {cond: true, cond2: true, value: 3.14}, + {cond: true, cond2: true, value: 42}, + {cond: true, cond2: true, value: 3.14}, + {cond: true, cond2: false, value2: 3.14}, + {cond: true, cond2: false, value2: 42}, + {cond: true, cond2: false, value2: 3.14}, + {cond: false}, + {cond: false}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { makeArray } from "shared-runtime"; + +function Component(props) { + const $ = _c(3); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = {}; + $[0] = t0; + } else { + t0 = $[0]; + } + const x = t0; + let t1; + if ($[1] !== props) { + let y; + if (props.cond) { + if (props.cond2) { + y = [props.value]; + } else { + y = [props.value2]; + } + } else { + y = []; + } + + y.push(x); + + t1 = [x, y]; + $[1] = props; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: true, cond2: true, value: 42 }], + sequentialRenders: [ + { cond: true, cond2: true, value: 3.14 }, + { cond: true, cond2: true, value: 42 }, + { cond: true, cond2: true, value: 3.14 }, + { cond: true, cond2: false, value2: 3.14 }, + { cond: true, cond2: false, value2: 42 }, + { cond: true, cond2: false, value2: 3.14 }, + { cond: false }, + { cond: false }, + ], +}; + +``` + +### Eval output +(kind: ok) [{},[3.14,"[[ cyclic ref *1 ]]"]] +[{},[42,"[[ cyclic ref *1 ]]"]] +[{},[3.14,"[[ cyclic ref *1 ]]"]] +[{},[3.14,"[[ cyclic ref *1 ]]"]] +[{},[42,"[[ cyclic ref *1 ]]"]] +[{},[3.14,"[[ cyclic ref *1 ]]"]] +[{},["[[ cyclic ref *1 ]]"]] +[{},["[[ cyclic ref *1 ]]"]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js new file mode 100644 index 0000000000000..0a9aa39defea4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js @@ -0,0 +1,37 @@ +import {makeArray} from 'shared-runtime'; + +function Component(props) { + const x = {}; + let y; + if (props.cond) { + if (props.cond2) { + y = [props.value]; + } else { + y = [props.value2]; + } + } else { + y = []; + } + // This should be inferred as ` y` s.t. `x` can still + // be independently memoized. *But* this also must properly + // extend the mutable range of the array literals in the + // if/else branches + y.push(x); + + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, cond2: true, value: 42}], + sequentialRenders: [ + {cond: true, cond2: true, value: 3.14}, + {cond: true, cond2: true, value: 42}, + {cond: true, cond2: true, value: 3.14}, + {cond: true, cond2: false, value2: 3.14}, + {cond: true, cond2: false, value2: 42}, + {cond: true, cond2: false, value2: 3.14}, + {cond: false}, + {cond: false}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md new file mode 100644 index 0000000000000..f58eed10fda5a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md @@ -0,0 +1,83 @@ + +## Input + +```javascript +function Component(props) { + const x = {}; + let y; + if (props.cond) { + y = [props.value]; + } else { + y = []; + } + // This should be inferred as ` y` s.t. `x` can still + // be independently memoized. *But* this also must properly + // extend the mutable range of the array literals in the + // if/else branches + y.push(x); + + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, value: 42}], + sequentialRenders: [ + {cond: true, value: 3.14}, + {cond: false, value: 3.14}, + {cond: true, value: 42}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(3); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = {}; + $[0] = t0; + } else { + t0 = $[0]; + } + const x = t0; + let t1; + if ($[1] !== props) { + let y; + if (props.cond) { + y = [props.value]; + } else { + y = []; + } + + y.push(x); + + t1 = [x, y]; + $[1] = props; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: true, value: 42 }], + sequentialRenders: [ + { cond: true, value: 3.14 }, + { cond: false, value: 3.14 }, + { cond: true, value: 42 }, + ], +}; + +``` + +### Eval output +(kind: ok) [{},[3.14,"[[ cyclic ref *1 ]]"]] +[{},["[[ cyclic ref *1 ]]"]] +[{},[42,"[[ cyclic ref *1 ]]"]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js new file mode 100644 index 0000000000000..732a1524cba2d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js @@ -0,0 +1,26 @@ +function Component(props) { + const x = {}; + let y; + if (props.cond) { + y = [props.value]; + } else { + y = []; + } + // This should be inferred as ` y` s.t. `x` can still + // be independently memoized. *But* this also must properly + // extend the mutable range of the array literals in the + // if/else branches + y.push(x); + + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true, value: 42}], + sequentialRenders: [ + {cond: true, value: 3.14}, + {cond: false, value: 3.14}, + {cond: true, value: 42}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md new file mode 100644 index 0000000000000..70551c8e9d7b0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md @@ -0,0 +1,72 @@ + +## Input + +```javascript +// @debug +function Component(props) { + const x = {}; + let y; + if (props.cond) { + y = {}; + } else { + y = {a: props.a}; + } + // This should be inferred as ` y` s.t. `x` can still + // be independently memoized. *But* this also must properly + // extend the mutable range of the object literals in the + // if/else branches + y.x = x; + + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: false, a: 'a!'}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @debug +function Component(props) { + const $ = _c(3); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = {}; + $[0] = t0; + } else { + t0 = $[0]; + } + const x = t0; + let t1; + if ($[1] !== props) { + let y; + if (props.cond) { + y = {}; + } else { + y = { a: props.a }; + } + + y.x = x; + + t1 = [x, y]; + $[1] = props; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: false, a: "a!" }], +}; + +``` + +### Eval output +(kind: ok) [{},{"a":"a!","x":"[[ cyclic ref *1 ]]"}] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js new file mode 100644 index 0000000000000..ba7133ff808df --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js @@ -0,0 +1,22 @@ +// @debug +function Component(props) { + const x = {}; + let y; + if (props.cond) { + y = {}; + } else { + y = {a: props.a}; + } + // This should be inferred as ` y` s.t. `x` can still + // be independently memoized. *But* this also must properly + // extend the mutable range of the object literals in the + // if/else branches + y.x = x; + + return [x, y]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: false, a: 'a!'}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md new file mode 100644 index 0000000000000..6574bd1966ed9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md @@ -0,0 +1,31 @@ + +## Input + +```javascript +function Component(props) { + return props.post.feedback.comments?.edges?.map(render); +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function Component(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.post.feedback.comments) { + t0 = props.post.feedback.comments?.edges?.map(render); + $[0] = props.post.feedback.comments; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js new file mode 100644 index 0000000000000..e8e0da392e9e7 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js @@ -0,0 +1,3 @@ +function Component(props) { + return props.post.feedback.comments?.edges?.map(render); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md new file mode 100644 index 0000000000000..f4689e5795552 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md @@ -0,0 +1,79 @@ + +## Input + +```javascript +import {mutate} from 'shared-runtime'; + +function useFoo(props) { + let x = []; + x.push(props.bar); + if (props.cond) { + x = {}; + x = []; + x.push(props.foo); + } else { + x = []; + x = []; + x.push(props.bar); + } + mutate(x); + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{bar: 'bar', foo: 'foo', cond: true}], + sequentialRenders: [ + {bar: 'bar', foo: 'foo', cond: true}, + {bar: 'bar', foo: 'foo', cond: true}, + {bar: 'bar', foo: 'foo', cond: false}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { mutate } from "shared-runtime"; + +function useFoo(props) { + const $ = _c(2); + let x; + if ($[0] !== props) { + x = []; + x.push(props.bar); + if (props.cond) { + x = []; + x.push(props.foo); + } else { + x = []; + x.push(props.bar); + } + + mutate(x); + $[0] = props; + $[1] = x; + } else { + x = $[1]; + } + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ bar: "bar", foo: "foo", cond: true }], + sequentialRenders: [ + { bar: "bar", foo: "foo", cond: true }, + { bar: "bar", foo: "foo", cond: true }, + { bar: "bar", foo: "foo", cond: false }, + ], +}; + +``` + +### Eval output +(kind: ok) ["foo","joe"] +["foo","joe"] +["bar","joe"] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js new file mode 100644 index 0000000000000..3e7078cfc7999 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js @@ -0,0 +1,27 @@ +import {mutate} from 'shared-runtime'; + +function useFoo(props) { + let x = []; + x.push(props.bar); + if (props.cond) { + x = {}; + x = []; + x.push(props.foo); + } else { + x = []; + x = []; + x.push(props.bar); + } + mutate(x); + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{bar: 'bar', foo: 'foo', cond: true}], + sequentialRenders: [ + {bar: 'bar', foo: 'foo', cond: true}, + {bar: 'bar', foo: 'foo', cond: true}, + {bar: 'bar', foo: 'foo', cond: false}, + ], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 7d7476dc74739..7140cad2f74bc 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -50,6 +50,7 @@ const skipFilter = new Set([ 'component', 'cond-deps-conditional-member-expr', 'conditional-break-labeled', + 'propagate-scope-deps-hir-fork/conditional-break-labeled', 'conditional-set-state-in-render', 'constant-computed', 'constant-propagation-phi', From 1a779207a7b85314e16d410b185d427702f22ebc Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:20 -0400 Subject: [PATCH 217/426] [compiler][test fixtures] Add enablePropagateDepsInHIR to forked tests Annotates fixtures added in #31030 with `@enablePropagateDepsInHIR` to fork behavior (and commit snapshot differences) ghstack-source-id: e423e8c42db62f1bb87562b770761be09fc8ffc6 Pull Request resolved: https://github.com/facebook/react/pull/31031 --- .../conditional-break-labeled.expect.md | 22 +++-- .../conditional-break-labeled.js | 1 + .../conditional-early-return.expect.md | 82 +++++++++++++------ .../conditional-early-return.js | 1 + .../conditional-on-mutable.expect.md | 27 +++--- .../conditional-on-mutable.js | 1 + ...rly-return-within-reactive-scope.expect.md | 29 ++++--- ...sted-early-return-within-reactive-scope.js | 1 + ...rly-return-within-reactive-scope.expect.md | 23 +++--- .../early-return-within-reactive-scope.js | 1 + ...-optional-call-chain-in-optional.expect.md | 15 ++-- ...or.todo-optional-call-chain-in-optional.ts | 1 + .../iife-return-modified-later-phi.expect.md | 14 ++-- .../iife-return-modified-later-phi.js | 1 + ...consequent-alternate-both-return.expect.md | 14 ++-- ...ted-in-consequent-alternate-both-return.js | 1 + ...rly-return-within-reactive-scope.expect.md | 25 +++--- ...tial-early-return-within-reactive-scope.js | 1 + ...ence-array-push-consecutive-phis.expect.md | 21 +++-- ...e-inference-array-push-consecutive-phis.js | 1 + .../phi-type-inference-array-push.expect.md | 14 ++-- .../phi-type-inference-array-push.js | 1 + ...hi-type-inference-property-store.expect.md | 15 ++-- .../phi-type-inference-property-store.js | 2 +- ...properties-inside-optional-chain.expect.md | 3 +- ...tional-properties-inside-optional-chain.js | 1 + ...ming-unconditional-with-mutation.expect.md | 15 ++-- ...sa-renaming-unconditional-with-mutation.js | 1 + 28 files changed, 210 insertions(+), 124 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md index 76648c251a101..f778c74037d32 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR /** * props.b *does* influence `a` */ @@ -29,13 +30,19 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; /** +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +/** * props.b *does* influence `a` */ function Component(props) { - const $ = _c(2); + const $ = _c(5); let a; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { a = []; a.push(props.a); bb0: { @@ -47,10 +54,13 @@ function Component(props) { } a.push(props.d); - $[0] = props; - $[1] = a; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; } else { - a = $[1]; + a = $[4]; } return a; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js index ccf983189cf71..770a4794fe075 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-break-labeled.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR /** * props.b *does* influence `a` */ diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md index 82537902bfa19..602859389e3a1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR /** * props.b does *not* influence `a` */ @@ -66,14 +67,15 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; /** +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +/** * props.b does *not* influence `a` */ function ComponentA(props) { - const $ = _c(3); + const $ = _c(5); let a_DEBUG; let t0; - if ($[0] !== props) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.d) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { a_DEBUG = []; @@ -85,12 +87,14 @@ function ComponentA(props) { a_DEBUG.push(props.d); } - $[0] = props; - $[1] = a_DEBUG; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.d; + $[3] = a_DEBUG; + $[4] = t0; } else { - a_DEBUG = $[1]; - t0 = $[2]; + a_DEBUG = $[3]; + t0 = $[4]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; @@ -102,9 +106,14 @@ function ComponentA(props) { * props.b *does* influence `a` */ function ComponentB(props) { - const $ = _c(2); + const $ = _c(5); let a; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { a = []; a.push(props.a); if (props.b) { @@ -112,10 +121,13 @@ function ComponentB(props) { } a.push(props.d); - $[0] = props; - $[1] = a; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; } else { - a = $[1]; + a = $[4]; } return a; } @@ -124,10 +136,15 @@ function ComponentB(props) { * props.b *does* influence `a`, but only in a way that is never observable */ function ComponentC(props) { - const $ = _c(3); + const $ = _c(6); let a; let t0; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { a = []; @@ -140,12 +157,15 @@ function ComponentC(props) { a.push(props.d); } - $[0] = props; - $[1] = a; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; + $[5] = t0; } else { - a = $[1]; - t0 = $[2]; + a = $[4]; + t0 = $[5]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; @@ -157,10 +177,15 @@ function ComponentC(props) { * props.b *does* influence `a` */ function ComponentD(props) { - const $ = _c(3); + const $ = _c(6); let a; let t0; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { a = []; @@ -173,12 +198,15 @@ function ComponentD(props) { a.push(props.d); } - $[0] = props; - $[1] = a; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; + $[5] = t0; } else { - a = $[1]; - t0 = $[2]; + a = $[4]; + t0 = $[5]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js index e0ed101409252..02edefc77f571 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-early-return.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR /** * props.b does *not* influence `a` */ diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md index 24c565b088d2f..17ff728051ddb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function ComponentA(props) { const a = []; const b = []; @@ -34,11 +35,11 @@ function mayMutate() {} ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function ComponentA(props) { - const $ = _c(2); + const $ = _c(4); let t0; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p1 || $[2] !== props.p2) { const a = []; const b = []; if (b) { @@ -49,18 +50,20 @@ function ComponentA(props) { } t0 = ; - $[0] = props; - $[1] = t0; + $[0] = props.p0; + $[1] = props.p1; + $[2] = props.p2; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } return t0; } function ComponentB(props) { - const $ = _c(2); + const $ = _c(4); let t0; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p1 || $[2] !== props.p2) { const a = []; const b = []; if (mayMutate(b)) { @@ -71,10 +74,12 @@ function ComponentB(props) { } t0 = ; - $[0] = props; - $[1] = t0; + $[0] = props.p0; + $[1] = props.p1; + $[2] = props.p2; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js index 0378ab655c1ef..d03e36aaab56c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/conditional-on-mutable.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function ComponentA(props) { const a = []; const b = []; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md index 2d33981f73fd1..476e1c017c655 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function Component(props) { let x = []; if (props.cond) { @@ -29,11 +30,11 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { - const $ = _c(5); + const $ = _c(7); let t0; - if ($[0] !== props) { + if ($[0] !== props.cond || $[1] !== props.a || $[2] !== props.b) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -41,12 +42,12 @@ function Component(props) { x.push(props.a); if (props.b) { let t1; - if ($[2] !== props.b) { + if ($[4] !== props.b) { t1 = [props.b]; - $[2] = props.b; - $[3] = t1; + $[4] = props.b; + $[5] = t1; } else { - t1 = $[3]; + t1 = $[5]; } const y = t1; x.push(y); @@ -58,20 +59,22 @@ function Component(props) { break bb0; } else { let t1; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { + if ($[6] === Symbol.for("react.memo_cache_sentinel")) { t1 = foo(); - $[4] = t1; + $[6] = t1; } else { - t1 = $[4]; + t1 = $[6]; } t0 = t1; break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.cond; + $[1] = props.a; + $[2] = props.b; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js index 53eb06bc591e4..c8c24172d79e6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function Component(props) { let x = []; if (props.cond) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md index 6c3525e9e77eb..bf54b52b59289 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR import {makeArray} from 'shared-runtime'; function Component(props) { @@ -41,13 +42,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { makeArray } from "shared-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(6); let t0; - if ($[0] !== props) { + if ($[0] !== props.cond || $[1] !== props.a || $[2] !== props.b) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -57,21 +58,23 @@ function Component(props) { break bb0; } else { let t1; - if ($[2] !== props.b) { + if ($[4] !== props.b) { t1 = makeArray(props.b); - $[2] = props.b; - $[3] = t1; + $[4] = props.b; + $[5] = t1; } else { - t1 = $[3]; + t1 = $[5]; } t0 = t1; break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.cond; + $[1] = props.a; + $[2] = props.b; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js index 7446d76fb320c..256eb46bc9280 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR import {makeArray} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md index 75c5d61d407f0..8b52187920cbe 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function useFoo(props: {value: {x: string; y: string} | null}) { const value = props.value; return createArray(value?.x, value?.y)?.join(', '); @@ -22,13 +23,13 @@ export const FIXTURE_ENTRYPONT = { ## Error ``` - 1 | function useFoo(props: {value: {x: string; y: string} | null}) { - 2 | const value = props.value; -> 3 | return createArray(value?.x, value?.y)?.join(', '); - | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional test block (3:3) - 4 | } - 5 | - 6 | function createArray(...args: Array): Array { + 2 | function useFoo(props: {value: {x: string; y: string} | null}) { + 3 | const value = props.value; +> 4 | return createArray(value?.x, value?.y)?.join(', '); + | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional test block (4:4) + 5 | } + 6 | + 7 | function createArray(...args: Array): Array { ``` \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts index 7ee50e0380288..0031bc770c678 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.ts @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function useFoo(props: {value: {x: string; y: string} | null}) { const value = props.value; return createArray(value?.x, value?.y)?.join(', '); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md index bed1c329f0d10..744824d0bd2c3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function Component(props) { const items = (() => { if (props.cond) { @@ -24,11 +25,11 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { - const $ = _c(2); + const $ = _c(3); let items; - if ($[0] !== props) { + if ($[0] !== props.cond || $[1] !== props.a) { let t0; if (props.cond) { t0 = []; @@ -38,10 +39,11 @@ function Component(props) { items = t0; items?.push(props.a); - $[0] = props; - $[1] = items; + $[0] = props.cond; + $[1] = props.a; + $[2] = items; } else { - items = $[1]; + items = $[2]; } return items; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js index f4f953d294e6f..4e8eb097de8a7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function Component(props) { const items = (() => { if (props.cond) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md index 8a20f9186b447..142fc9cefe64c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR import {makeObject_Primitives} from 'shared-runtime'; function Component(props) { @@ -25,13 +26,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { makeObject_Primitives } from "shared-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(3); let t0; - if ($[0] !== props) { + if ($[0] !== props.cond || $[1] !== props.value) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const object = makeObject_Primitives(); @@ -45,10 +46,11 @@ function Component(props) { break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.cond; + $[1] = props.value; + $[2] = t0; } else { - t0 = $[1]; + t0 = $[2]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js index 94a142d033708..2386448adfbbc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/object-mutated-in-consequent-alternate-both-return.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR import {makeObject_Primitives} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md index 398161f0c6a24..324eb714fc89b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function Component(props) { let x = []; let y = null; @@ -28,12 +29,12 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { - const $ = _c(4); + const $ = _c(6); let y; let t0; - if ($[0] !== props) { + if ($[0] !== props.cond || $[1] !== props.a || $[2] !== props.b) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -43,11 +44,11 @@ function Component(props) { break bb0; } else { let t1; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { t1 = foo(); - $[3] = t1; + $[5] = t1; } else { - t1 = $[3]; + t1 = $[5]; } y = t1; if (props.b) { @@ -56,12 +57,14 @@ function Component(props) { } } } - $[0] = props; - $[1] = y; - $[2] = t0; + $[0] = props.cond; + $[1] = props.a; + $[2] = props.b; + $[3] = y; + $[4] = t0; } else { - y = $[1]; - t0 = $[2]; + y = $[3]; + t0 = $[4]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js index 66d68242b8bb6..d54f650c36bbe 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function Component(props) { let x = []; let y = null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md index f17bcc92cb7ce..4ae80006678c6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR import {makeArray} from 'shared-runtime'; function Component(props) { @@ -45,11 +46,11 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { makeArray } from "shared-runtime"; function Component(props) { - const $ = _c(3); + const $ = _c(6); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -59,7 +60,12 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props) { + if ( + $[1] !== props.cond || + $[2] !== props.cond2 || + $[3] !== props.value || + $[4] !== props.value2 + ) { let y; if (props.cond) { if (props.cond2) { @@ -74,10 +80,13 @@ function Component(props) { y.push(x); t1 = [x, y]; - $[1] = props; - $[2] = t1; + $[1] = props.cond; + $[2] = props.cond2; + $[3] = props.value; + $[4] = props.value2; + $[5] = t1; } else { - t1 = $[2]; + t1 = $[5]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js index 0a9aa39defea4..9173848b49b90 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push-consecutive-phis.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR import {makeArray} from 'shared-runtime'; function Component(props) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md index f58eed10fda5a..0b756a648ec23 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function Component(props) { const x = {}; let y; @@ -34,9 +35,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { - const $ = _c(3); + const $ = _c(4); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -46,7 +47,7 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props) { + if ($[1] !== props.cond || $[2] !== props.value) { let y; if (props.cond) { y = [props.value]; @@ -57,10 +58,11 @@ function Component(props) { y.push(x); t1 = [x, y]; - $[1] = props; - $[2] = t1; + $[1] = props.cond; + $[2] = props.value; + $[3] = t1; } else { - t1 = $[2]; + t1 = $[3]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js index 732a1524cba2d..0b60f4e44315d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-array-push.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function Component(props) { const x = {}; let y; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md index 70551c8e9d7b0..1bfaeb1c84a57 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @debug +// @debug @enablePropagateDepsInHIR function Component(props) { const x = {}; let y; @@ -30,9 +30,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @debug +import { c as _c } from "react/compiler-runtime"; // @debug @enablePropagateDepsInHIR function Component(props) { - const $ = _c(3); + const $ = _c(4); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -42,7 +42,7 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props) { + if ($[1] !== props.cond || $[2] !== props.a) { let y; if (props.cond) { y = {}; @@ -53,10 +53,11 @@ function Component(props) { y.x = x; t1 = [x, y]; - $[1] = props; - $[2] = t1; + $[1] = props.cond; + $[2] = props.a; + $[3] = t1; } else { - t1 = $[2]; + t1 = $[3]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js index ba7133ff808df..3611da08d2fbd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.js @@ -1,4 +1,4 @@ -// @debug +// @debug @enablePropagateDepsInHIR function Component(props) { const x = {}; let y; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md index 6574bd1966ed9..6db3983d10751 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR function Component(props) { return props.post.feedback.comments?.edges?.map(render); } @@ -11,7 +12,7 @@ function Component(props) { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(2); let t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js index e8e0da392e9e7..58ad2a210fab5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR function Component(props) { return props.post.feedback.comments?.edges?.map(render); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md index f4689e5795552..1cb3cf2474b6a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.expect.md @@ -2,6 +2,7 @@ ## Input ```javascript +// @enablePropagateDepsInHIR import {mutate} from 'shared-runtime'; function useFoo(props) { @@ -35,13 +36,13 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR import { mutate } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { x = []; x.push(props.bar); if (props.cond) { @@ -53,10 +54,12 @@ function useFoo(props) { } mutate(x); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js index 3e7078cfc7999..99e28942268bd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-with-mutation.js @@ -1,3 +1,4 @@ +// @enablePropagateDepsInHIR import {mutate} from 'shared-runtime'; function useFoo(props) { From 8c89fa76430b3d9fbecd6d535c93171d22f0377f Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:20 -0400 Subject: [PATCH 218/426] [compiler][hir-rewrite] Infer non-null props, destructure source Followup from #30894. This adds a new flagged mode `enablePropagateScopeDepsInHIR: "enabled_with_optimizations"`, under which we infer more hoistable loads: - it's always safe to evaluate loads from `props` (i.e. first parameter of a `component`) - destructuring sources are safe to evaluate loads from (e.g. given `{x} = obj`, we infer that it's safe to evaluate obj.y) - computed load sources are safe to evaluate loads from (e.g. given `arr[0]`, we can infer that it's safe to evaluate arr.length) ghstack-source-id: 32f3bb72e9f85922825579bd785d636f4ccf724d Pull Request resolved: https://github.com/facebook/react/pull/31033 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 139 ++++++++++++------ .../infer-component-props-non-null.expect.md | 60 ++++++++ .../infer-component-props-non-null.tsx | 20 +++ .../infer-non-null-destructure.expect.md | 91 ++++++++++++ .../infer-non-null-destructure.ts | 23 +++ 5 files changed, 289 insertions(+), 44 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index 941c60dea9d4f..ff50113b6660c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -8,6 +8,7 @@ import { HIRFunction, Identifier, IdentifierId, + InstructionId, Place, ReactiveScopeDependency, ScopeId, @@ -66,7 +67,7 @@ export function collectHoistablePropertyLoads( fn: HIRFunction, temporaries: ReadonlyMap, ): ReadonlyMap { - const nodes = collectPropertyLoadsInBlocks(fn, temporaries); + const nodes = collectNonNullsInBlocks(fn, temporaries); propagateNonNull(fn, nodes); const nodesKeyedByScopeId = new Map(); @@ -165,7 +166,7 @@ type PropertyLoadNode = class Tree { roots: Map = new Map(); - #getOrCreateRoot(identifier: Identifier): PropertyLoadNode { + getOrCreateRoot(identifier: Identifier): PropertyLoadNode { /** * Reads from a statically scoped variable are always safe in JS, * with the exception of TDZ (not addressed by this pass). @@ -207,17 +208,15 @@ class Tree { } getPropertyLoadNode(n: ReactiveScopeDependency): PropertyLoadNode { - CompilerError.invariant(n.path.length > 0, { - reason: - '[CollectHoistablePropertyLoads] Expected property node, found root node', - loc: GeneratedSource, - }); /** * We add ReactiveScopeDependencies according to instruction ordering, * so all subpaths of a PropertyLoad should already exist * (e.g. a.b is added before a.b.c), */ - let currNode = this.#getOrCreateRoot(n.identifier); + let currNode = this.getOrCreateRoot(n.identifier); + if (n.path.length === 0) { + return currNode; + } for (let i = 0; i < n.path.length - 1; i++) { currNode = assertNonNull(currNode.properties.get(n.path[i].property)); } @@ -226,10 +225,44 @@ class Tree { } } -function collectPropertyLoadsInBlocks( +function pushPropertyLoadNode( + loadSource: Identifier, + loadSourceNode: PropertyLoadNode, + instrId: InstructionId, + knownImmutableIdentifiers: Set, + result: Set, +): void { + /** + * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges + * are not valid with respect to current instruction id numbering. + * We use attached reactive scope ranges as a proxy for mutable range, but this + * is an overestimate as (1) scope ranges merge and align to form valid program + * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to + * non-mutable identifiers. + * + * See comment at top of function for why we track known immutable identifiers. + */ + const isMutableAtInstr = + loadSource.mutableRange.end > loadSource.mutableRange.start + 1 && + loadSource.scope != null && + inRange({id: instrId}, loadSource.scope.range); + if ( + !isMutableAtInstr || + knownImmutableIdentifiers.has(loadSourceNode.fullPath.identifier.id) + ) { + let curr: PropertyLoadNode | null = loadSourceNode; + while (curr != null) { + result.add(curr); + curr = curr.parent; + } + } +} + +function collectNonNullsInBlocks( fn: HIRFunction, temporaries: ReadonlyMap, ): ReadonlyMap { + const tree = new Tree(); /** * Due to current limitations of mutable range inference, there are edge cases in * which we infer known-immutable values (e.g. props or hook params) to have a @@ -238,53 +271,70 @@ function collectPropertyLoadsInBlocks( * We track known immutable identifiers to reduce regressions (as PropagateScopeDeps * is being rewritten to HIR). */ - const knownImmutableIdentifiers = new Set(); + const knownImmutableIdentifiers = new Set(); if (fn.fnType === 'Component' || fn.fnType === 'Hook') { for (const p of fn.params) { if (p.kind === 'Identifier') { - knownImmutableIdentifiers.add(p.identifier); + knownImmutableIdentifiers.add(p.identifier.id); } } } - const tree = new Tree(); + /** + * Known non-null objects such as functional component props can be safely + * read from any block. + */ + const knownNonNullIdentifiers = new Set(); + if ( + fn.fnType === 'Component' && + fn.params.length > 0 && + fn.params[0].kind === 'Identifier' + ) { + const identifier = fn.params[0].identifier; + knownNonNullIdentifiers.add(tree.getOrCreateRoot(identifier)); + } const nodes = new Map(); for (const [_, block] of fn.body.blocks) { - const assumedNonNullObjects = new Set(); + const assumedNonNullObjects = new Set( + knownNonNullIdentifiers, + ); for (const instr of block.instructions) { if (instr.value.kind === 'PropertyLoad') { - const property = getProperty( - instr.value.object, - instr.value.property, - temporaries, + const source = temporaries.get(instr.value.object.identifier.id) ?? { + identifier: instr.value.object.identifier, + path: [], + }; + pushPropertyLoadNode( + instr.value.object.identifier, + tree.getPropertyLoadNode(source), + instr.id, + knownImmutableIdentifiers, + assumedNonNullObjects, ); - const propertyNode = tree.getPropertyLoadNode(property); - const object = instr.value.object.identifier; - /** - * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges - * are not valid with respect to current instruction id numbering. - * We use attached reactive scope ranges as a proxy for mutable range, but this - * is an overestimate as (1) scope ranges merge and align to form valid program - * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to - * non-mutable identifiers. - * - * See comment at top of function for why we track known immutable identifiers. - */ - const isMutableAtInstr = - object.mutableRange.end > object.mutableRange.start + 1 && - object.scope != null && - inRange(instr, object.scope.range); - if ( - !isMutableAtInstr || - knownImmutableIdentifiers.has(propertyNode.fullPath.identifier) - ) { - let curr = propertyNode.parent; - while (curr != null) { - assumedNonNullObjects.add(curr); - curr = curr.parent; - } + } else if (instr.value.kind === 'Destructure') { + const source = instr.value.value.identifier.id; + const sourceNode = temporaries.get(source); + if (sourceNode != null) { + pushPropertyLoadNode( + instr.value.value.identifier, + tree.getPropertyLoadNode(sourceNode), + instr.id, + knownImmutableIdentifiers, + assumedNonNullObjects, + ); + } + } else if (instr.value.kind === 'ComputedLoad') { + const source = instr.value.object.identifier.id; + const sourceNode = temporaries.get(source); + if (sourceNode != null) { + pushPropertyLoadNode( + instr.value.object.identifier, + tree.getPropertyLoadNode(sourceNode), + instr.id, + knownImmutableIdentifiers, + assumedNonNullObjects, + ); } } - // TODO handle destructuring } nodes.set(block.id, { @@ -449,10 +499,11 @@ function propagateNonNull( ); for (const [id, node] of nodes) { - node.assumedNonNullObjects = Set_union( + const assumedNonNullObjects = Set_union( assertNonNull(fromEntry.get(id)), assertNonNull(fromExit.get(id)), ); + node.assumedNonNullObjects = assumedNonNullObjects; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.expect.md new file mode 100644 index 0000000000000..da9ab95fb6b53 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.expect.md @@ -0,0 +1,60 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR +import {identity, Stringify} from 'shared-runtime'; + +function Foo(props) { + /** + * props.value should be inferred as the dependency of this scope + * since we know that props is safe to read from (i.e. non-null) + * as it is arg[0] of a component function + */ + const arr = []; + if (cond) { + arr.push(identity(props.value)); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{value: 2}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +import { identity, Stringify } from "shared-runtime"; + +function Foo(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.value) { + const arr = []; + if (cond) { + arr.push(identity(props.value)); + } + + t0 = ; + $[0] = props.value; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ value: 2 }], +}; + +``` + +### Eval output +(kind: exception) cond is not defined \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.tsx new file mode 100644 index 0000000000000..d5aa3534d4dc3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-component-props-non-null.tsx @@ -0,0 +1,20 @@ +// @enablePropagateDepsInHIR +import {identity, Stringify} from 'shared-runtime'; + +function Foo(props) { + /** + * props.value should be inferred as the dependency of this scope + * since we know that props is safe to read from (i.e. non-null) + * as it is arg[0] of a component function + */ + const arr = []; + if (cond) { + arr.push(identity(props.value)); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{value: 2}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.expect.md new file mode 100644 index 0000000000000..faed26bc8aef4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.expect.md @@ -0,0 +1,91 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR +import {identity, useIdentity} from 'shared-runtime'; + +function useFoo({arg, cond}: {arg: number; cond: boolean}) { + const maybeObj = useIdentity({value: arg}); + const {value} = maybeObj; + useIdentity(null); + /** + * maybeObj.value should be inferred as the dependency of this scope + * since we know that maybeObj is safe to read from (i.e. non-null) + * due to the above destructuring instruction + */ + const arr = []; + if (cond) { + arr.push(identity(maybeObj.value)); + } + return {arr, value}; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{arg: 2, cond: false}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +import { identity, useIdentity } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(10); + const { arg, cond } = t0; + let t1; + if ($[0] !== arg) { + t1 = { value: arg }; + $[0] = arg; + $[1] = t1; + } else { + t1 = $[1]; + } + const maybeObj = useIdentity(t1); + const { value } = maybeObj; + useIdentity(null); + let arr; + if ($[2] !== cond || $[3] !== maybeObj.value) { + arr = []; + if (cond) { + let t2; + if ($[5] !== maybeObj.value) { + t2 = identity(maybeObj.value); + $[5] = maybeObj.value; + $[6] = t2; + } else { + t2 = $[6]; + } + arr.push(t2); + } + $[2] = cond; + $[3] = maybeObj.value; + $[4] = arr; + } else { + arr = $[4]; + } + let t2; + if ($[7] !== arr || $[8] !== value) { + t2 = { arr, value }; + $[7] = arr; + $[8] = value; + $[9] = t2; + } else { + t2 = $[9]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ arg: 2, cond: false }], +}; + +``` + +### Eval output +(kind: ok) {"arr":[],"value":2} \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.ts new file mode 100644 index 0000000000000..f67991df7254e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-non-null-destructure.ts @@ -0,0 +1,23 @@ +// @enablePropagateDepsInHIR +import {identity, useIdentity} from 'shared-runtime'; + +function useFoo({arg, cond}: {arg: number; cond: boolean}) { + const maybeObj = useIdentity({value: arg}); + const {value} = maybeObj; + useIdentity(null); + /** + * maybeObj.value should be inferred as the dependency of this scope + * since we know that maybeObj is safe to read from (i.e. non-null) + * due to the above destructuring instruction + */ + const arr = []; + if (cond) { + arr.push(identity(maybeObj.value)); + } + return {arr, value}; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{arg: 2, cond: false}], +}; From 58a3ca3b47f6a51cea48ea95ded26c9887baca38 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:21 -0400 Subject: [PATCH 219/426] [compiler][hir-rewrite] Cleanup Identifier -> IdentifierId Since removing ExitSSA, Identifier and IdentifierId should mean the same thing ghstack-source-id: 076cacbe8360e716b0555088043502823f9ee72e Pull Request resolved: https://github.com/facebook/react/pull/31034 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 66 ++----------------- .../src/HIR/PropagateScopeDependenciesHIR.ts | 49 +++++++++++++- 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index ff50113b6660c..4f642e57a65f3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -9,7 +9,6 @@ import { Identifier, IdentifierId, InstructionId, - Place, ReactiveScopeDependency, ScopeId, } from './HIR'; @@ -88,61 +87,6 @@ export type BlockInfo = { assumedNonNullObjects: ReadonlySet; }; -export function getProperty( - object: Place, - propertyName: string, - temporaries: ReadonlyMap, -): ReactiveScopeDependency { - /* - * (1) Get the base object either from the temporary sidemap (e.g. a LoadLocal) - * or a deep copy of an existing property dependency. - * Example 1: - * $0 = LoadLocal x - * $1 = PropertyLoad $0.y - * getProperty($0, ...) -> resolvedObject = x, resolvedDependency = null - * - * Example 2: - * $0 = LoadLocal x - * $1 = PropertyLoad $0.y - * $2 = PropertyLoad $1.z - * getProperty($1, ...) -> resolvedObject = null, resolvedDependency = x.y - * - * Example 3: - * $0 = Call(...) - * $1 = PropertyLoad $0.y - * getProperty($0, ...) -> resolvedObject = null, resolvedDependency = null - */ - const resolvedDependency = temporaries.get(object.identifier.id); - - /** - * (2) Push the last PropertyLoad - * TODO(mofeiZ): understand optional chaining - */ - let property: ReactiveScopeDependency; - if (resolvedDependency == null) { - property = { - identifier: object.identifier, - path: [{property: propertyName, optional: false}], - }; - } else { - property = { - identifier: resolvedDependency.identifier, - path: [ - ...resolvedDependency.path, - {property: propertyName, optional: false}, - ], - }; - } - return property; -} - -export function resolveTemporary( - place: Place, - temporaries: ReadonlyMap, -): Identifier { - return temporaries.get(place.identifier.id) ?? place.identifier; -} - /** * Tree data structure to dedupe property loads (e.g. a.b.c) * and make computing sets intersections simpler. @@ -152,7 +96,7 @@ type RootNode = { parent: null; // Recorded to make later computations simpler fullPath: ReactiveScopeDependency; - root: Identifier; + root: IdentifierId; }; type PropertyLoadNode = @@ -164,18 +108,18 @@ type PropertyLoadNode = | RootNode; class Tree { - roots: Map = new Map(); + roots: Map = new Map(); getOrCreateRoot(identifier: Identifier): PropertyLoadNode { /** * Reads from a statically scoped variable are always safe in JS, * with the exception of TDZ (not addressed by this pass). */ - let rootNode = this.roots.get(identifier); + let rootNode = this.roots.get(identifier.id); if (rootNode === undefined) { rootNode = { - root: identifier, + root: identifier.id, properties: new Map(), fullPath: { identifier, @@ -183,7 +127,7 @@ class Tree { }, parent: null, }; - this.roots.set(identifier, rootNode); + this.roots.set(identifier.id, rootNode); } return rootNode; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index 4c7dac004d80a..1fe218c352818 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -20,7 +20,6 @@ import { import { BlockInfo, collectHoistablePropertyLoads, - getProperty, } from './CollectHoistablePropertyLoads'; import { ScopeBlockTraversal, @@ -220,6 +219,54 @@ function collectTemporariesSidemap( return temporaries; } +function getProperty( + object: Place, + propertyName: string, + temporaries: ReadonlyMap, +): ReactiveScopeDependency { + /* + * (1) Get the base object either from the temporary sidemap (e.g. a LoadLocal) + * or a deep copy of an existing property dependency. + * Example 1: + * $0 = LoadLocal x + * $1 = PropertyLoad $0.y + * getProperty($0, ...) -> resolvedObject = x, resolvedDependency = null + * + * Example 2: + * $0 = LoadLocal x + * $1 = PropertyLoad $0.y + * $2 = PropertyLoad $1.z + * getProperty($1, ...) -> resolvedObject = null, resolvedDependency = x.y + * + * Example 3: + * $0 = Call(...) + * $1 = PropertyLoad $0.y + * getProperty($0, ...) -> resolvedObject = null, resolvedDependency = null + */ + const resolvedDependency = temporaries.get(object.identifier.id); + + /** + * (2) Push the last PropertyLoad + * TODO(mofeiZ): understand optional chaining + */ + let property: ReactiveScopeDependency; + if (resolvedDependency == null) { + property = { + identifier: object.identifier, + path: [{property: propertyName, optional: false}], + }; + } else { + property = { + identifier: resolvedDependency.identifier, + path: [ + ...resolvedDependency.path, + {property: propertyName, optional: false}, + ], + }; + } + return property; +} + type Decl = { id: InstructionId; scope: Stack; From 5d12e9e10b9957bc131ec77e013e1a76e4f32eb6 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:22 -0400 Subject: [PATCH 220/426] [compiler] repro for dep merging edge case (non-hir) Found when writing #31037, summary copied from comments: This is an extreme edge case and not code we'd expect any reasonable developer to write. In most cases e.g. `(a?.b != null ? a.b : DEFAULT)`, we do want to take a dependency on `a?.b`. I found this trying to come up with edge cases that break the current dependency + CFG merging logic. I think it makes sense to error on the side of correctness. After all, we still take `a` as a dependency if users write `a != null ? a.b : DEFAULT`, and the same fix (understanding the ` != null` test expression) works for both. Can be convinced otherwise though! ghstack-source-id: cc06afda59f7681e228495f5e35a596c20f875f5 Pull Request resolved: https://github.com/facebook/react/pull/31035 --- ...e-uncond-optional-chain-and-cond.expect.md | 88 +++++++++++++++++++ ...ug-merge-uncond-optional-chain-and-cond.ts | 31 +++++++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 3 files changed, 120 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md new file mode 100644 index 0000000000000..9a95e7dc875b4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md @@ -0,0 +1,88 @@ + +## Input + +```javascript +import {identity} from 'shared-runtime'; + +/** + * Evaluator failure: + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) {} + * [[ (exception in render) TypeError: Cannot read properties of null (reading 'title_text') ]] + * Forget: + * (kind: ok) {} + * {} + */ +/** + * Very contrived text fixture showing that it's technically incorrect to merge + * a conditional dependency (e.g. dep.path in `cond ? dep.path : ...`) and an + * unconditionally evaluated optional chain (`dep?.path`). + * + * + * when screen is non-null, useFoo returns { title: null } or "(not null)" + * when screen is null, useFoo throws + */ +function useFoo({screen}: {screen: null | undefined | {title_text: null}}) { + return screen?.title_text != null + ? '(not null)' + : identity({title: screen.title_text}); +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{screen: null}], + sequentialRenders: [{screen: {title_bar: undefined}}, {screen: null}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { identity } from "shared-runtime"; + +/** + * Evaluator failure: + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) {} + * [[ (exception in render) TypeError: Cannot read properties of null (reading 'title_text') ]] + * Forget: + * (kind: ok) {} + * {} + */ +/** + * Very contrived text fixture showing that it's technically incorrect to merge + * a conditional dependency (e.g. dep.path in `cond ? dep.path : ...`) and an + * unconditionally evaluated optional chain (`dep?.path`). + * + * + * when screen is non-null, useFoo returns { title: null } or "(not null)" + * when screen is null, useFoo throws + */ +function useFoo(t0) { + const $ = _c(2); + const { screen } = t0; + let t1; + if ($[0] !== screen?.title_text) { + t1 = + screen?.title_text != null + ? "(not null)" + : identity({ title: screen.title_text }); + $[0] = screen?.title_text; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ screen: null }], + sequentialRenders: [{ screen: { title_bar: undefined } }, { screen: null }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.ts new file mode 100644 index 0000000000000..bb361e3c9fefd --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.ts @@ -0,0 +1,31 @@ +import {identity} from 'shared-runtime'; + +/** + * Evaluator failure: + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) {} + * [[ (exception in render) TypeError: Cannot read properties of null (reading 'title_text') ]] + * Forget: + * (kind: ok) {} + * {} + */ +/** + * Very contrived text fixture showing that it's technically incorrect to merge + * a conditional dependency (e.g. dep.path in `cond ? dep.path : ...`) and an + * unconditionally evaluated optional chain (`dep?.path`). + * + * + * when screen is non-null, useFoo returns { title: null } or "(not null)" + * when screen is null, useFoo throws + */ +function useFoo({screen}: {screen: null | undefined | {title_text: null}}) { + return screen?.title_text != null + ? '(not null)' + : identity({title: screen.title_text}); +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{screen: null}], + sequentialRenders: [{screen: {title_bar: undefined}}, {screen: null}], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 7140cad2f74bc..0ae22a643b326 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -478,6 +478,7 @@ const skipFilter = new Set([ 'fbt/bug-fbt-plural-multiple-function-calls', 'fbt/bug-fbt-plural-multiple-mixed-call-tag', 'bug-invalid-hoisting-functionexpr', + 'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond', 'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block', 'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope', 'bug-codegen-inline-iife', From 2cbea245cca4044f02c4c231a7f86c8062074579 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:23 -0400 Subject: [PATCH 221/426] [compiler][fixtures] Patch error-handling edge case in snap evaluator Fix edge case in which we incorrectly returned a cached exception instead of trying to rerender with new props. ghstack-source-id: 843fb85df4a2ae7a88f296104fb16b5f9a34c76e Pull Request resolved: https://github.com/facebook/react/pull/31082 --- .../throw-before-scope-starts.expect.md | 2 +- .../packages/snap/src/sprout/evaluator.ts | 45 +++++++++++++------ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/throw-before-scope-starts.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/throw-before-scope-starts.expect.md index 4f04ef7fdc1ba..dd7509c48c4c4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/throw-before-scope-starts.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/throw-before-scope-starts.expect.md @@ -75,7 +75,7 @@ export const FIXTURE_ENTRYPOINT = { ### Eval output (kind: ok) [[ (exception in render) Error: throw with error! ]] -[[ (exception in render) Error: throw with error! ]] +[2] [[ (exception in render) Error: throw with error! ]] [[ (exception in render) TypeError: Cannot read properties of undefined (reading 'b') ]] [null] diff --git a/compiler/packages/snap/src/sprout/evaluator.ts b/compiler/packages/snap/src/sprout/evaluator.ts index 27cbe55858f60..77e8044fb5ed5 100644 --- a/compiler/packages/snap/src/sprout/evaluator.ts +++ b/compiler/packages/snap/src/sprout/evaluator.ts @@ -60,6 +60,7 @@ const ExportSchema = z.object({ FIXTURE_ENTRYPOINT: EntrypointSchema, }); +const NO_ERROR_SENTINEL = Symbol(); /** * Wraps WrapperTestComponent in an error boundary to simplify re-rendering * when an exception is thrown. @@ -67,31 +68,47 @@ const ExportSchema = z.object({ */ class WrapperTestComponentWithErrorBoundary extends React.Component< {fn: any; params: Array}, - {hasError: boolean; error: any} + {errorFromLastRender: any} > { - propsErrorMap: MutableRefObject>; + /** + * Limit retries of the child component by caching seen errors. + */ + propsErrorMap: Map; + lastProps: any | null; + // lastProps: object | null; constructor(props: any) { super(props); - this.state = {hasError: false, error: null}; - this.propsErrorMap = React.createRef() as MutableRefObject>; - this.propsErrorMap.current = new Map(); + this.lastProps = null; + this.propsErrorMap = new Map(); + this.state = { + errorFromLastRender: NO_ERROR_SENTINEL, + }; } static getDerivedStateFromError(error: any) { - return {hasError: true, error: error}; + // Reschedule a second render that immediately returns the cached error + return {errorFromLastRender: error}; } override componentDidUpdate() { - if (this.state.hasError) { - this.setState({hasError: false, error: null}); + if (this.state.errorFromLastRender !== NO_ERROR_SENTINEL) { + // Reschedule a third render that immediately returns the cached error + this.setState({errorFromLastRender: NO_ERROR_SENTINEL}); } } override render() { - if (this.state.hasError) { - this.propsErrorMap.current!.set( - this.props, - `[[ (exception in render) ${this.state.error?.toString()} ]]`, - ); + if ( + this.state.errorFromLastRender !== NO_ERROR_SENTINEL && + this.props === this.lastProps + ) { + /** + * The last render errored, cache the error message to avoid running the + * test fixture more than once + */ + const errorMsg = `[[ (exception in render) ${this.state.errorFromLastRender?.toString()} ]]`; + this.propsErrorMap.set(this.lastProps, errorMsg); + return errorMsg; } - const cachedError = this.propsErrorMap.current!.get(this.props); + this.lastProps = this.props; + const cachedError = this.propsErrorMap.get(this.props); if (cachedError != null) { return cachedError; } From c67e241c1656dea4ece22a4ee5c25b6b36d0ca75 Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Mon, 30 Sep 2024 12:24:24 -0400 Subject: [PATCH 222/426] [compiler] Renames and no-op refactor for next PR Rename for clarity: - `CollectHoistablePropertyLoads:Tree` -> `CollectHoistablePropertyLoads:PropertyPathRegistry` - `getPropertyLoadNode` -> `getOrCreateProperty` - `getOrCreateRoot` -> `getOrCreateIdentifier` - `PropertyLoadNode` -> `PropertyPathNode` Refactor to CFG joining logic for `CollectHoistablePropertyLoads`. We now write to the same set of inferredNonNullObjects when traversing from entry and exit blocks. This is more correct, as non-nulls inferred from a forward traversal should be included when computing the backward traversal (and vice versa). This fix is needed by an edge case in #31036 Added invariant into fixed-point iteration to terminate (instead of infinite looping). ghstack-source-id: 1e8eb2d566b649ede93de9a9c13dad09b96416a5 Pull Request resolved: https://github.com/facebook/react/pull/31036 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 160 ++++++++---------- .../src/HIR/DeriveMinimalDependenciesHIR.ts | 25 ++- .../src/HIR/HIR.ts | 18 +- 3 files changed, 95 insertions(+), 108 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index 4f642e57a65f3..cb778c329226b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -4,6 +4,7 @@ import {Set_intersect, Set_union, getOrInsertDefault} from '../Utils/utils'; import { BasicBlock, BlockId, + DependencyPathEntry, GeneratedSource, HIRFunction, Identifier, @@ -66,7 +67,9 @@ export function collectHoistablePropertyLoads( fn: HIRFunction, temporaries: ReadonlyMap, ): ReadonlyMap { - const nodes = collectNonNullsInBlocks(fn, temporaries); + const registry = new PropertyPathRegistry(); + + const nodes = collectNonNullsInBlocks(fn, temporaries, registry); propagateNonNull(fn, nodes); const nodesKeyedByScopeId = new Map(); @@ -84,33 +87,33 @@ export function collectHoistablePropertyLoads( export type BlockInfo = { block: BasicBlock; - assumedNonNullObjects: ReadonlySet; + assumedNonNullObjects: ReadonlySet; }; /** - * Tree data structure to dedupe property loads (e.g. a.b.c) + * PropertyLoadRegistry data structure to dedupe property loads (e.g. a.b.c) * and make computing sets intersections simpler. */ type RootNode = { - properties: Map; + properties: Map; parent: null; // Recorded to make later computations simpler fullPath: ReactiveScopeDependency; root: IdentifierId; }; -type PropertyLoadNode = +type PropertyPathNode = | { - properties: Map; - parent: PropertyLoadNode; + properties: Map; + parent: PropertyPathNode; fullPath: ReactiveScopeDependency; } | RootNode; -class Tree { +class PropertyPathRegistry { roots: Map = new Map(); - getOrCreateRoot(identifier: Identifier): PropertyLoadNode { + getOrCreateIdentifier(identifier: Identifier): PropertyPathNode { /** * Reads from a statically scoped variable are always safe in JS, * with the exception of TDZ (not addressed by this pass). @@ -132,49 +135,61 @@ class Tree { return rootNode; } - static #getOrCreateProperty( - node: PropertyLoadNode, - property: string, - ): PropertyLoadNode { - let child = node.properties.get(property); + static getOrCreatePropertyEntry( + parent: PropertyPathNode, + entry: DependencyPathEntry, + ): PropertyPathNode { + if (entry.optional) { + CompilerError.throwTodo({ + reason: 'handle optional nodes', + loc: GeneratedSource, + }); + } + let child = parent.properties.get(entry.property); if (child == null) { child = { properties: new Map(), - parent: node, + parent: parent, fullPath: { - identifier: node.fullPath.identifier, - path: node.fullPath.path.concat([{property, optional: false}]), + identifier: parent.fullPath.identifier, + path: parent.fullPath.path.concat(entry), }, }; - node.properties.set(property, child); + parent.properties.set(entry.property, child); } return child; } - getPropertyLoadNode(n: ReactiveScopeDependency): PropertyLoadNode { + getOrCreateProperty(n: ReactiveScopeDependency): PropertyPathNode { /** * We add ReactiveScopeDependencies according to instruction ordering, * so all subpaths of a PropertyLoad should already exist * (e.g. a.b is added before a.b.c), */ - let currNode = this.getOrCreateRoot(n.identifier); + let currNode = this.getOrCreateIdentifier(n.identifier); if (n.path.length === 0) { return currNode; } for (let i = 0; i < n.path.length - 1; i++) { - currNode = assertNonNull(currNode.properties.get(n.path[i].property)); + currNode = PropertyPathRegistry.getOrCreatePropertyEntry( + currNode, + n.path[i], + ); } - return Tree.#getOrCreateProperty(currNode, n.path.at(-1)!.property); + return PropertyPathRegistry.getOrCreatePropertyEntry( + currNode, + n.path.at(-1)!, + ); } } -function pushPropertyLoadNode( - loadSource: Identifier, - loadSourceNode: PropertyLoadNode, +function addNonNullPropertyPath( + source: Identifier, + sourceNode: PropertyPathNode, instrId: InstructionId, knownImmutableIdentifiers: Set, - result: Set, + result: Set, ): void { /** * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges @@ -187,26 +202,22 @@ function pushPropertyLoadNode( * See comment at top of function for why we track known immutable identifiers. */ const isMutableAtInstr = - loadSource.mutableRange.end > loadSource.mutableRange.start + 1 && - loadSource.scope != null && - inRange({id: instrId}, loadSource.scope.range); + source.mutableRange.end > source.mutableRange.start + 1 && + source.scope != null && + inRange({id: instrId}, source.scope.range); if ( !isMutableAtInstr || - knownImmutableIdentifiers.has(loadSourceNode.fullPath.identifier.id) + knownImmutableIdentifiers.has(sourceNode.fullPath.identifier.id) ) { - let curr: PropertyLoadNode | null = loadSourceNode; - while (curr != null) { - result.add(curr); - curr = curr.parent; - } + result.add(sourceNode); } } function collectNonNullsInBlocks( fn: HIRFunction, temporaries: ReadonlyMap, + registry: PropertyPathRegistry, ): ReadonlyMap { - const tree = new Tree(); /** * Due to current limitations of mutable range inference, there are edge cases in * which we infer known-immutable values (e.g. props or hook params) to have a @@ -227,18 +238,18 @@ function collectNonNullsInBlocks( * Known non-null objects such as functional component props can be safely * read from any block. */ - const knownNonNullIdentifiers = new Set(); + const knownNonNullIdentifiers = new Set(); if ( fn.fnType === 'Component' && fn.params.length > 0 && fn.params[0].kind === 'Identifier' ) { const identifier = fn.params[0].identifier; - knownNonNullIdentifiers.add(tree.getOrCreateRoot(identifier)); + knownNonNullIdentifiers.add(registry.getOrCreateIdentifier(identifier)); } const nodes = new Map(); for (const [_, block] of fn.body.blocks) { - const assumedNonNullObjects = new Set( + const assumedNonNullObjects = new Set( knownNonNullIdentifiers, ); for (const instr of block.instructions) { @@ -247,9 +258,9 @@ function collectNonNullsInBlocks( identifier: instr.value.object.identifier, path: [], }; - pushPropertyLoadNode( + addNonNullPropertyPath( instr.value.object.identifier, - tree.getPropertyLoadNode(source), + registry.getOrCreateProperty(source), instr.id, knownImmutableIdentifiers, assumedNonNullObjects, @@ -258,9 +269,9 @@ function collectNonNullsInBlocks( const source = instr.value.value.identifier.id; const sourceNode = temporaries.get(source); if (sourceNode != null) { - pushPropertyLoadNode( + addNonNullPropertyPath( instr.value.value.identifier, - tree.getPropertyLoadNode(sourceNode), + registry.getOrCreateProperty(sourceNode), instr.id, knownImmutableIdentifiers, assumedNonNullObjects, @@ -270,9 +281,9 @@ function collectNonNullsInBlocks( const source = instr.value.object.identifier.id; const sourceNode = temporaries.get(source); if (sourceNode != null) { - pushPropertyLoadNode( + addNonNullPropertyPath( instr.value.object.identifier, - tree.getPropertyLoadNode(sourceNode), + registry.getOrCreateProperty(sourceNode), instr.id, knownImmutableIdentifiers, assumedNonNullObjects, @@ -314,7 +325,6 @@ function propagateNonNull( nodeId: BlockId, direction: 'forward' | 'backward', traversalState: Map, - nonNullObjectsByBlock: Map>, ): boolean { /** * Avoid re-visiting computed or currently active nodes, which can @@ -345,7 +355,6 @@ function propagateNonNull( pred, direction, traversalState, - nonNullObjectsByBlock, ); changed ||= neighborChanged; } @@ -374,38 +383,36 @@ function propagateNonNull( const neighborAccesses = Set_intersect( Array.from(neighbors) .filter(n => traversalState.get(n) === 'done') - .map(n => assertNonNull(nonNullObjectsByBlock.get(n))), + .map(n => assertNonNull(nodes.get(n)).assumedNonNullObjects), ); - const prevObjects = assertNonNull(nonNullObjectsByBlock.get(nodeId)); - const newObjects = Set_union(prevObjects, neighborAccesses); + const prevObjects = assertNonNull(nodes.get(nodeId)).assumedNonNullObjects; + const mergedObjects = Set_union(prevObjects, neighborAccesses); - nonNullObjectsByBlock.set(nodeId, newObjects); + assertNonNull(nodes.get(nodeId)).assumedNonNullObjects = mergedObjects; traversalState.set(nodeId, 'done'); - changed ||= prevObjects.size !== newObjects.size; + changed ||= prevObjects.size !== mergedObjects.size; return changed; } - const fromEntry = new Map>(); - const fromExit = new Map>(); - for (const [blockId, blockInfo] of nodes) { - fromEntry.set(blockId, blockInfo.assumedNonNullObjects); - fromExit.set(blockId, blockInfo.assumedNonNullObjects); - } const traversalState = new Map(); const reversedBlocks = [...fn.body.blocks]; reversedBlocks.reverse(); - let i = 0; let changed; + let i = 0; do { - i++; + CompilerError.invariant(i++ < 100, { + reason: + '[CollectHoistablePropertyLoads] fixed point iteration did not terminate after 100 loops', + loc: GeneratedSource, + }); + changed = false; for (const [blockId] of fn.body.blocks) { const forwardChanged = recursivelyPropagateNonNull( blockId, 'forward', traversalState, - fromEntry, ); changed ||= forwardChanged; } @@ -415,43 +422,14 @@ function propagateNonNull( blockId, 'backward', traversalState, - fromExit, ); changed ||= backwardChanged; } traversalState.clear(); } while (changed); - - /** - * TODO: validate against meta internal code, then remove in future PR. - * Currently cannot come up with a case that requires fixed-point iteration. - */ - CompilerError.invariant(i <= 2, { - reason: 'require fixed-point iteration', - description: `#iterations = ${i}`, - loc: GeneratedSource, - }); - - CompilerError.invariant( - fromEntry.size === fromExit.size && fromEntry.size === nodes.size, - { - reason: - 'bad sizes after calculating fromEntry + fromExit ' + - `${fromEntry.size} ${fromExit.size} ${nodes.size}`, - loc: GeneratedSource, - }, - ); - - for (const [id, node] of nodes) { - const assumedNonNullObjects = Set_union( - assertNonNull(fromEntry.get(id)), - assertNonNull(fromExit.get(id)), - ); - node.assumedNonNullObjects = assumedNonNullObjects; - } } -function assertNonNull, U>( +export function assertNonNull, U>( value: T | null | undefined, source?: string, ): T { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts index ecc1844b006aa..f2bb0b31f05c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts @@ -19,16 +19,17 @@ const ENABLE_DEBUG_INVARIANTS = true; export class ReactiveScopeDependencyTreeHIR { #roots: Map = new Map(); - #getOrCreateRoot(identifier: Identifier, isNonNull: boolean): DependencyNode { + #getOrCreateRoot( + identifier: Identifier, + accessType: PropertyAccessType, + ): DependencyNode { // roots can always be accessed unconditionally in JS let rootNode = this.#roots.get(identifier); if (rootNode === undefined) { rootNode = { properties: new Map(), - accessType: isNonNull - ? PropertyAccessType.NonNullAccess - : PropertyAccessType.Access, + accessType, }; this.#roots.set(identifier, rootNode); } @@ -37,7 +38,7 @@ export class ReactiveScopeDependencyTreeHIR { addDependency(dep: ReactiveScopePropertyDependency): void { const {path} = dep; - let currNode = this.#getOrCreateRoot(dep.identifier, false); + let currNode = this.#getOrCreateRoot(dep.identifier, MIN_ACCESS_TYPE); const accessType = PropertyAccessType.Access; @@ -45,8 +46,11 @@ export class ReactiveScopeDependencyTreeHIR { for (const property of path) { // all properties read 'on the way' to a dependency are marked as 'access' - let currChild = getOrMakeProperty(currNode, property.property); - currChild.accessType = merge(currChild.accessType, accessType); + let currChild = makeOrMergeProperty( + currNode, + property.property, + accessType, + ); currNode = currChild; } @@ -251,17 +255,20 @@ function printSubtree( return results; } -function getOrMakeProperty( +function makeOrMergeProperty( node: DependencyNode, property: string, + accessType: PropertyAccessType, ): DependencyNode { let child = node.properties.get(property); if (child == null) { child = { properties: new Map(), - accessType: MIN_ACCESS_TYPE, + accessType, }; node.properties.set(property, child); + } else { + child.accessType = merge(child.accessType, accessType); } return child; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 30408ab032b35..615ec18feb962 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -874,13 +874,7 @@ export type InstructionValue = }; loc: SourceLocation; } - | { - kind: 'StoreLocal'; - lvalue: LValue; - value: Place; - type: t.FlowType | t.TSType | null; - loc: SourceLocation; - } + | StoreLocal | { kind: 'StoreContext'; lvalue: { @@ -1123,6 +1117,13 @@ export type Primitive = { export type JSXText = {kind: 'JSXText'; value: string; loc: SourceLocation}; +export type StoreLocal = { + kind: 'StoreLocal'; + lvalue: LValue; + value: Place; + type: t.FlowType | t.TSType | null; + loc: SourceLocation; +}; export type PropertyLoad = { kind: 'PropertyLoad'; object: Place; @@ -1496,7 +1497,8 @@ export type ReactiveScopeDeclaration = { scope: ReactiveScope; // the scope in which the variable was originally declared }; -export type DependencyPath = Array<{property: string; optional: boolean}>; +export type DependencyPathEntry = {property: string; optional: boolean}; +export type DependencyPath = Array; export type ReactiveScopeDependency = { identifier: Identifier; path: DependencyPath; From 326832a56d41b4462919f9efe69916712ca87a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 30 Sep 2024 12:45:13 -0700 Subject: [PATCH 223/426] [Flight] Serialize Error Values (#31104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The idea is that the RSC protocol is a superset of Structured Clone. #25687 One exception that we left out was serializing Error objects as values. We serialize "throws" or "rejections" as Error (regardless of their type) but not Error values. This fixes that by serializing `Error` objects. We don't include digest in this case since we don't call `onError` and it's not really expected that you'd log it on the server with some way to look it up. In general this is not super useful outside throws. Especially since we hide their values in prod. However, there is one case where it is quite useful. When you replay console logs in DEV you might often log an Error object within the scope of a Server Component. E.g. the default RSC error handling just console.error and error object. Before this would just be an empty object due to our lax console log serialization: Screenshot 2024-09-30 at 2 24 03 PM After: Screenshot 2024-09-30 at 2 36 48 PM TODO for a follow up: Flight Reply direction. This direction doesn't actually serialize thrown errors because they always reject the serialization. --- .../react-client/src/ReactFlightClient.js | 74 +++++++++---------- .../src/__tests__/ReactFlight-test.js | 40 ++++++++++ .../react-server/src/ReactFlightServer.js | 36 +++++++++ 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 83c509dab46a8..98a52c4ec4a9a 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -1287,6 +1287,21 @@ function parseModelString( createFormData, ); } + case 'Z': { + // Error + if (__DEV__) { + const ref = value.slice(2); + return getOutlinedModel( + response, + ref, + parentObject, + key, + resolveErrorDev, + ); + } else { + return resolveErrorProd(response); + } + } case 'i': { // Iterator const ref = value.slice(2); @@ -1881,11 +1896,7 @@ function formatV8Stack( } type ErrorWithDigest = Error & {digest?: string}; -function resolveErrorProd( - response: Response, - id: number, - digest: string, -): void { +function resolveErrorProd(response: Response): Error { if (__DEV__) { // These errors should never make it into a build so we don't need to encode them in codes.json // eslint-disable-next-line react-internal/prod-error-codes @@ -1899,25 +1910,17 @@ function resolveErrorProd( ' may provide additional details about the nature of the error.', ); error.stack = 'Error: ' + error.message; - (error: any).digest = digest; - const errorWithDigest: ErrorWithDigest = (error: any); - const chunks = response._chunks; - const chunk = chunks.get(id); - if (!chunk) { - chunks.set(id, createErrorChunk(response, errorWithDigest)); - } else { - triggerErrorOnChunk(chunk, errorWithDigest); - } + return error; } function resolveErrorDev( response: Response, - id: number, - digest: string, - message: string, - stack: ReactStackTrace, - env: string, -): void { + errorInfo: {message: string, stack: ReactStackTrace, env: string, ...}, +): Error { + const message: string = errorInfo.message; + const stack: ReactStackTrace = errorInfo.stack; + const env: string = errorInfo.env; + if (!__DEV__) { // These errors should never make it into a build so we don't need to encode them in codes.json // eslint-disable-next-line react-internal/prod-error-codes @@ -1957,16 +1960,8 @@ function resolveErrorDev( } } - (error: any).digest = digest; (error: any).environmentName = env; - const errorWithDigest: ErrorWithDigest = (error: any); - const chunks = response._chunks; - const chunk = chunks.get(id); - if (!chunk) { - chunks.set(id, createErrorChunk(response, errorWithDigest)); - } else { - triggerErrorOnChunk(chunk, errorWithDigest); - } + return error; } function resolvePostponeProd(response: Response, id: number): void { @@ -2622,17 +2617,20 @@ function processFullStringRow( } case 69 /* "E" */: { const errorInfo = JSON.parse(row); + let error; if (__DEV__) { - resolveErrorDev( - response, - id, - errorInfo.digest, - errorInfo.message, - errorInfo.stack, - errorInfo.env, - ); + error = resolveErrorDev(response, errorInfo); + } else { + error = resolveErrorProd(response); + } + (error: any).digest = errorInfo.digest; + const errorWithDigest: ErrorWithDigest = (error: any); + const chunks = response._chunks; + const chunk = chunks.get(id); + if (!chunk) { + chunks.set(id, createErrorChunk(response, errorWithDigest)); } else { - resolveErrorProd(response, id, errorInfo.digest); + triggerErrorOnChunk(chunk, errorWithDigest); } return; } diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 34986dc623de8..27db069ef324f 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -653,6 +653,46 @@ describe('ReactFlight', () => { `); }); + it('can transport Error objects as values', async () => { + function ComponentClient({prop}) { + return ` + is error: ${prop instanceof Error} + message: ${prop.message} + stack: ${normalizeCodeLocInfo(prop.stack).split('\n').slice(0, 2).join('\n')} + environmentName: ${prop.environmentName} + `; + } + const Component = clientReference(ComponentClient); + + function ServerComponent() { + const error = new Error('hello'); + return ; + } + + const transport = ReactNoopFlightServer.render(); + + await act(async () => { + ReactNoop.render(await ReactNoopFlightClient.read(transport)); + }); + + if (__DEV__) { + expect(ReactNoop).toMatchRenderedOutput(` + is error: true + message: hello + stack: Error: hello + in ServerComponent (at **) + environmentName: Server + `); + } else { + expect(ReactNoop).toMatchRenderedOutput(` + is error: true + message: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error. + stack: Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error. + environmentName: undefined + `); + } + }); + it('can transport cyclic objects', async () => { function ComponentClient({prop}) { expect(prop.obj.obj.obj).toBe(prop.obj.obj); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 5d79482de0186..19c40c214b918 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -2688,6 +2688,9 @@ function renderModelDestructive( if (typeof FormData === 'function' && value instanceof FormData) { return serializeFormData(request, value); } + if (value instanceof Error) { + return serializeErrorValue(request, value); + } if (enableBinaryFlight) { if (value instanceof ArrayBuffer) { @@ -3114,6 +3117,36 @@ function emitPostponeChunk( request.completedErrorChunks.push(processedChunk); } +function serializeErrorValue(request: Request, error: Error): string { + if (__DEV__) { + let message; + let stack: ReactStackTrace; + let env = (0, request.environmentName)(); + try { + // eslint-disable-next-line react-internal/safe-string-coercion + message = String(error.message); + stack = filterStackTrace(request, error, 0); + const errorEnv = (error: any).environmentName; + if (typeof errorEnv === 'string') { + // This probably came from another FlightClient as a pass through. + // Keep the environment name. + env = errorEnv; + } + } catch (x) { + message = 'An error occurred but serializing the error message failed.'; + stack = []; + } + const errorInfo = {message, stack, env}; + const id = outlineModel(request, errorInfo); + return '$Z' + id.toString(16); + } else { + // In prod we don't emit any information about this Error object to avoid + // unintentional leaks. Since this doesn't actually throw on the server + // we don't go through onError and so don't register any digest neither. + return '$Z'; + } +} + function emitErrorChunk( request: Request, id: number, @@ -3403,6 +3436,9 @@ function renderConsoleValue( if (typeof FormData === 'function' && value instanceof FormData) { return serializeFormData(request, value); } + if (value instanceof Error) { + return serializeErrorValue(request, value); + } if (enableBinaryFlight) { if (value instanceof ArrayBuffer) { From 654e387d7eac113ddbf85f8a9029d1af7117679e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 30 Sep 2024 22:39:20 -0700 Subject: [PATCH 224/426] [Flight] Serialize Server Components Props in DEV (#31105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to show props in React DevTools when inspecting a Server Component. I currently drastically limit the object depth that's serialized since this is very implicit and you can have heavy objects on the server. We previously was using the general outlineModel to outline ReactComponentInfo but we weren't consistently using it everywhere which could cause some bugs with the parsing when it got deduped on the client. It also lead to the weird feature detect of `isReactComponent`. It also meant that this serialization was using the plain serialization instead of `renderConsoleValue` which means we couldn't safely serialize arbitrary debug info that isn't serializable there. So the main change here is to call `outlineComponentInfo` and have that always write every "Server Component" instance as outlined and in a way that lets its props be serialized using `renderConsoleValue`. Screenshot 2024-10-01 at 1 25 05 AM --- .../react-client/src/ReactFlightClient.js | 21 +- .../src/__tests__/ReactFlight-test.js | 33 +++ .../src/backend/fiber/renderer.js | 3 +- .../react-devtools-shared/src/hydration.js | 58 ++++- .../__tests__/ReactFlightDOMBrowser-test.js | 8 +- .../react-server/src/ReactFlightServer.js | 218 +++++++++++------- packages/shared/ReactTypes.js | 1 + 7 files changed, 245 insertions(+), 97 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 98a52c4ec4a9a..2f60ccddb4b4d 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -2640,11 +2640,22 @@ function processFullStringRow( } case 68 /* "D" */: { if (__DEV__) { - const debugInfo: ReactComponentInfo | ReactAsyncInfo = parseModel( - response, - row, - ); - resolveDebugInfo(response, id, debugInfo); + const chunk: ResolvedModelChunk = + createResolvedModelChunk(response, row); + initializeModelChunk(chunk); + const initializedChunk: SomeChunk = + chunk; + if (initializedChunk.status === INITIALIZED) { + resolveDebugInfo(response, id, initializedChunk.value); + } else { + // TODO: This is not going to resolve in the right order if there's more than one. + chunk.then( + v => resolveDebugInfo(response, id, v), + e => { + // Ignore debug info errors for now. Unnecessary noise. + }, + ); + } return; } // Fallthrough to share the error with Console entries. diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 27db069ef324f..857ce99868d9b 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -308,6 +308,10 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: { + firstName: 'Seb', + lastName: 'Smith', + }, }, ] : undefined, @@ -347,6 +351,10 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: { + firstName: 'Seb', + lastName: 'Smith', + }, }, ] : undefined, @@ -2665,6 +2673,9 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: { + transport: expect.arrayContaining([]), + }, }, ] : undefined, @@ -2683,6 +2694,7 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: {}, }, ] : undefined, @@ -2698,6 +2710,7 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in myLazy (at **)\n in lazyInitializer (at **)' : undefined, + props: {}, }, ] : undefined, @@ -2713,6 +2726,7 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: {}, }, ] : undefined, @@ -2787,6 +2801,9 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: { + transport: expect.arrayContaining([]), + }, }, ] : undefined, @@ -2804,6 +2821,9 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in ServerComponent (at **)' : undefined, + props: { + children: {}, + }, }, ] : undefined, @@ -2820,6 +2840,7 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: {}, }, ] : undefined, @@ -2978,6 +2999,7 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: {}, }, { env: 'B', @@ -3108,6 +3130,9 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Object. (at **)' : undefined, + props: { + firstName: 'Seb', + }, }; expect(getDebugInfo(greeting)).toEqual([ greetInfo, @@ -3119,6 +3144,14 @@ describe('ReactFlight', () => { stack: gate(flag => flag.enableOwnerStacks) ? ' in Greeting (at **)' : undefined, + props: { + children: expect.objectContaining({ + type: 'span', + props: { + children: ['Hello, ', 'Seb'], + }, + }), + }, }, ]); // The owner that created the span was the outer server component. diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 4fac8839ae799..9732bf105ca6c 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -4348,8 +4348,7 @@ export function attach( const componentInfo = virtualInstance.data; const key = typeof componentInfo.key === 'string' ? componentInfo.key : null; - const props = null; // TODO: Track props on ReactComponentInfo; - + const props = componentInfo.props == null ? null : componentInfo.props; const owners: null | Array = getOwnersListFromInstance(virtualInstance); diff --git a/packages/react-devtools-shared/src/hydration.js b/packages/react-devtools-shared/src/hydration.js index c5b78135e74a2..c21efe40a88fa 100644 --- a/packages/react-devtools-shared/src/hydration.js +++ b/packages/react-devtools-shared/src/hydration.js @@ -216,16 +216,19 @@ export function dehydrate( if (level >= LEVEL_THRESHOLD && !isPathAllowedCheck) { return createDehydrated(type, true, data, cleaned, path); } - return data.map((item, i) => - dehydrate( - item, + const arr: Array = []; + for (let i = 0; i < data.length; i++) { + arr[i] = dehydrateKey( + data, + i, cleaned, unserializable, path.concat([i]), isPathAllowed, isPathAllowedCheck ? 1 : level + 1, - ), - ); + ); + } + return arr; case 'html_all_collection': case 'typed_array': @@ -311,8 +314,9 @@ export function dehydrate( } = {}; getAllEnumerableKeys(data).forEach(key => { const name = key.toString(); - object[name] = dehydrate( - data[key], + object[name] = dehydrateKey( + data, + key, cleaned, unserializable, path.concat([name]), @@ -373,6 +377,46 @@ export function dehydrate( } } +function dehydrateKey( + parent: Object, + key: number | string | symbol, + cleaned: Array>, + unserializable: Array>, + path: Array, + isPathAllowed: (path: Array) => boolean, + level: number = 0, +): $PropertyType { + try { + return dehydrate( + parent[key], + cleaned, + unserializable, + path, + isPathAllowed, + level, + ); + } catch (error) { + let preview = ''; + if ( + typeof error === 'object' && + error !== null && + typeof error.stack === 'string' + ) { + preview = error.stack; + } else if (typeof error === 'string') { + preview = error; + } + cleaned.push(path); + return { + inspectable: false, + preview_short: '[Exception]', + preview_long: preview ? '[Exception: ' + preview + ']' : '[Exception]', + name: preview, + type: 'unknown', + }; + } +} + export function fillInPath( object: Object, data: DehydratedData, diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js index 0408a63fc512f..882c0bbb01969 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMBrowser-test.js @@ -709,7 +709,7 @@ describe('ReactFlightDOMBrowser', () => { expect(container.innerHTML).toBe(expectedHtml); if (__DEV__) { - const resolvedPath1b = await response.value[0].props.children[1]._payload; + const resolvedPath1b = response.value[0].props.children[1]; expect(resolvedPath1b._owner).toEqual( expect.objectContaining({ @@ -1028,8 +1028,10 @@ describe('ReactFlightDOMBrowser', () => { expect(flightResponse).toContain('(loading everything)'); expect(flightResponse).toContain('(loading sidebar)'); expect(flightResponse).toContain('(loading posts)'); - expect(flightResponse).not.toContain(':friends:'); - expect(flightResponse).not.toContain(':name:'); + if (!__DEV__) { + expect(flightResponse).not.toContain(':friends:'); + expect(flightResponse).not.toContain(':name:'); + } await serverAct(() => { resolveFriends(); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 19c40c214b918..5db03d628146f 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -1148,14 +1148,20 @@ function renderFunctionComponent( ? null : filterStackTrace(request, task.debugStack, 1); // $FlowFixMe[cannot-write] + componentDebugInfo.props = props; + // $FlowFixMe[cannot-write] componentDebugInfo.debugStack = task.debugStack; // $FlowFixMe[cannot-write] componentDebugInfo.debugTask = task.debugTask; + } else { + // $FlowFixMe[cannot-write] + componentDebugInfo.props = props; } // We outline this model eagerly so that we can refer to by reference as an owner. // If we had a smarter way to dedupe we might not have to do this if there ends up // being no references to this as an owner. - outlineModel(request, componentDebugInfo); + + outlineComponentInfo(request, componentDebugInfo); emitDebugChunk(request, componentDebugID, componentDebugInfo); // We've emitted the latest environment for this task so we track that. @@ -1582,6 +1588,13 @@ function renderClientElement( } else if (keyPath !== null) { key = keyPath + ',' + key; } + if (__DEV__) { + if (task.debugOwner !== null) { + // Ensure we outline this owner if it is the first time we see it. + // So that we can refer to it directly. + outlineComponentInfo(request, task.debugOwner); + } + } const element = __DEV__ ? enableOwnerStacks ? [ @@ -1702,6 +1715,7 @@ function renderElement( task.debugStack === null ? null : filterStackTrace(request, task.debugStack, 1), + props: props, debugStack: task.debugStack, debugTask: task.debugTask, }; @@ -2128,7 +2142,7 @@ function serializeSet(request: Request, set: Set): string { function serializeConsoleMap( request: Request, - counter: {objectCount: number}, + counter: {objectLimit: number}, map: Map, ): string { // Like serializeMap but for renderConsoleValue. @@ -2139,7 +2153,7 @@ function serializeConsoleMap( function serializeConsoleSet( request: Request, - counter: {objectCount: number}, + counter: {objectLimit: number}, set: Set, ): string { // Like serializeMap but for renderConsoleValue. @@ -2263,23 +2277,6 @@ function escapeStringValue(value: string): string { } } -function isReactComponentInfo(value: any): boolean { - // TODO: We don't currently have a brand check on ReactComponentInfo. Reconsider. - return ( - ((typeof value.debugTask === 'object' && - value.debugTask !== null && - // $FlowFixMe[method-unbinding] - typeof value.debugTask.run === 'function') || - value.debugStack instanceof Error) && - (enableOwnerStacks - ? isArray((value: any).stack) || (value: any).stack === null - : typeof (value: any).stack === 'undefined') && - typeof value.name === 'string' && - typeof value.env === 'string' && - value.owner !== undefined - ); -} - let modelRoot: null | ReactClientValue = false; function renderModel( @@ -2795,25 +2792,6 @@ function renderModelDestructive( ); } if (__DEV__) { - if (isReactComponentInfo(value)) { - // This looks like a ReactComponentInfo. We can't serialize the ConsoleTask object so we - // need to omit it before serializing. - const componentDebugInfo: Omit< - ReactComponentInfo, - 'debugTask' | 'debugStack', - > = { - name: (value: any).name, - env: (value: any).env, - key: (value: any).key, - owner: (value: any).owner, - }; - if (enableOwnerStacks) { - // $FlowFixMe[cannot-write] - componentDebugInfo.stack = (value: any).stack; - } - return componentDebugInfo; - } - if (objectName(value) !== 'Object') { callWithDebugContextInDEV(request, task, () => { console.error( @@ -3241,7 +3219,7 @@ function emitDebugChunk( // We use the console encoding so that we can dedupe objects but don't necessarily // use the full serialization that requires a task. - const counter = {objectCount: 0}; + const counter = {objectLimit: 500}; function replacer( this: | {+[key: string | number]: ReactClientValue} @@ -3265,6 +3243,61 @@ function emitDebugChunk( request.completedRegularChunks.push(processedChunk); } +function outlineComponentInfo( + request: Request, + componentInfo: ReactComponentInfo, +): void { + if (!__DEV__) { + // These errors should never make it into a build so we don't need to encode them in codes.json + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error( + 'outlineComponentInfo should never be called in production mode. This is a bug in React.', + ); + } + + if (request.writtenObjects.has(componentInfo)) { + // Already written + return; + } + + if (componentInfo.owner != null) { + // Ensure the owner is already outlined. + outlineComponentInfo(request, componentInfo.owner); + } + + // Limit the number of objects we write to prevent emitting giant props objects. + let objectLimit = 10; + if (componentInfo.stack != null) { + // Ensure we have enough object limit to encode the stack trace. + objectLimit += componentInfo.stack.length; + } + + // We use the console encoding so that we can dedupe objects but don't necessarily + // use the full serialization that requires a task. + const counter = {objectLimit}; + + // We can't serialize the ConsoleTask/Error objects so we need to omit them before serializing. + const componentDebugInfo: Omit< + ReactComponentInfo, + 'debugTask' | 'debugStack', + > = { + name: componentInfo.name, + env: componentInfo.env, + key: componentInfo.key, + owner: componentInfo.owner, + }; + if (enableOwnerStacks) { + // $FlowFixMe[cannot-write] + componentDebugInfo.stack = componentInfo.stack; + } + // Ensure we serialize props after the stack to favor the stack being complete. + // $FlowFixMe[cannot-write] + componentDebugInfo.props = componentInfo.props; + + const id = outlineConsoleValue(request, counter, componentDebugInfo); + request.writtenObjects.set(componentInfo, serializeByValueID(id)); +} + function emitTypedArrayChunk( request: Request, id: number, @@ -3322,7 +3355,7 @@ function serializeEval(source: string): string { // in the depth it can encode. function renderConsoleValue( request: Request, - counter: {objectCount: number}, + counter: {objectLimit: number}, parent: | {+[propertyName: string | number]: ReactClientValue} | $ReadOnlyArray, @@ -3366,23 +3399,64 @@ function renderConsoleValue( } } - if (counter.objectCount > 500) { + const writtenObjects = request.writtenObjects; + const existingReference = writtenObjects.get(value); + if (existingReference !== undefined) { + // We've already emitted this as a real object, so we can + // just refer to that by its existing reference. + return existingReference; + } + + if (counter.objectLimit <= 0) { // We've reached our max number of objects to serialize across the wire so we serialize this // as a marker so that the client can error when this is accessed by the console. return serializeLimitedObject(); } - counter.objectCount++; + counter.objectLimit--; - const writtenObjects = request.writtenObjects; - const existingReference = writtenObjects.get(value); - // $FlowFixMe[method-unbinding] - if (typeof value.then === 'function') { - if (existingReference !== undefined) { - // We've seen this promise before, so we can just refer to the same result. - return existingReference; + switch ((value: any).$$typeof) { + case REACT_ELEMENT_TYPE: { + const element: ReactElement = (value: any); + + if (element._owner != null) { + outlineComponentInfo(request, element._owner); + } + if (enableOwnerStacks) { + let debugStack: null | ReactStackTrace = null; + if (element._debugStack != null) { + // Outline the debug stack so that it doesn't get cut off. + debugStack = filterStackTrace(request, element._debugStack, 1); + const stackId = outlineConsoleValue( + request, + {objectLimit: debugStack.length + 2}, + debugStack, + ); + request.writtenObjects.set(debugStack, serializeByValueID(stackId)); + } + return [ + REACT_ELEMENT_TYPE, + element.type, + element.key, + element.props, + element._owner, + debugStack, + element._store.validated, + ]; + } + + return [ + REACT_ELEMENT_TYPE, + element.type, + element.key, + element.props, + element._owner, + ]; } + } + // $FlowFixMe[method-unbinding] + if (typeof value.then === 'function') { const thenable: Thenable = (value: any); switch (thenable.status) { case 'fulfilled': { @@ -3416,12 +3490,6 @@ function renderConsoleValue( return serializeInfinitePromise(); } - if (existingReference !== undefined) { - // We've already emitted this as a real object, so we can - // just refer to that by its existing reference. - return existingReference; - } - if (isArray(value)) { return value; } @@ -3503,25 +3571,6 @@ function renderConsoleValue( return Array.from((value: any)); } - if (isReactComponentInfo(value)) { - // This looks like a ReactComponentInfo. We can't serialize the ConsoleTask object so we - // need to omit it before serializing. - const componentDebugInfo: Omit< - ReactComponentInfo, - 'debugTask' | 'debugStack', - > = { - name: (value: any).name, - env: (value: any).env, - key: (value: any).key, - owner: (value: any).owner, - }; - if (enableOwnerStacks) { - // $FlowFixMe[cannot-write] - componentDebugInfo.stack = (value: any).stack; - } - return componentDebugInfo; - } - // $FlowFixMe[incompatible-return] return value; } @@ -3602,7 +3651,7 @@ function renderConsoleValue( function outlineConsoleValue( request: Request, - counter: {objectCount: number}, + counter: {objectLimit: number}, model: ReactClientValue, ): number { if (!__DEV__) { @@ -3629,7 +3678,9 @@ function outlineConsoleValue( value, ); } catch (x) { - return 'unknown value'; + return ( + 'Unknown Value: React could not send it from the server.\n' + x.message + ); } } @@ -3660,7 +3711,7 @@ function emitConsoleChunk( ); } - const counter = {objectCount: 0}; + const counter = {objectLimit: 500}; function replacer( this: | {+[key: string | number]: ReactClientValue} @@ -3677,10 +3728,17 @@ function emitConsoleChunk( value, ); } catch (x) { - return 'unknown value'; + return ( + 'Unknown Value: React could not send it from the server.\n' + x.message + ); } } + // Ensure the owner is already outlined. + if (owner != null) { + outlineComponentInfo(request, owner); + } + // TODO: Don't double badge if this log came from another Flight Client. const env = (0, request.environmentName)(); const payload = [methodName, stackTrace, owner, env]; @@ -3704,7 +3762,7 @@ function forwardDebugInfo( // We outline this model eagerly so that we can refer to by reference as an owner. // If we had a smarter way to dedupe we might not have to do this if there ends up // being no references to this as an owner. - outlineModel(request, debugInfo[i]); + outlineComponentInfo(request, (debugInfo[i]: any)); } emitDebugChunk(request, id, debugInfo[i]); } diff --git a/packages/shared/ReactTypes.js b/packages/shared/ReactTypes.js index 7d51fbe4725d3..54eccd5538dd8 100644 --- a/packages/shared/ReactTypes.js +++ b/packages/shared/ReactTypes.js @@ -193,6 +193,7 @@ export type ReactComponentInfo = { +key?: null | string, +owner?: null | ReactComponentInfo, +stack?: null | ReactStackTrace, + +props?: null | {[name: string]: mixed}, // Stashed Data for the Specific Execution Environment. Not part of the transport protocol +debugStack?: null | Error, +debugTask?: null | ConsoleTask, From 40357fe63071950b0bba304657a003755aec4e30 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 1 Oct 2024 14:03:48 +0100 Subject: [PATCH 225/426] fix[react-devtools]: request hook initialization inside http server response (#31102) Fixes https://github.com/facebook/react/issues/31100. There are 2 things: 1. In https://github.com/facebook/react/pull/30987, we've introduced a breaking change: importing `react-devtools-core` is no longer enough for installing React DevTools global Hook. You need to call `initialize`, in which you may provide initial settings. I am not adding settings here, because it is not implemented, and there are no plans for supporting this. 2. Calling `installHook` is not necessary inside `standalone.js`, because this script is running inside Electron wrapper (which is just a UI, not the app that we are debugging). We will loose the ability to use React DevTools on this React application, but I guess thats fine. --- packages/react-devtools-core/src/standalone.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-devtools-core/src/standalone.js b/packages/react-devtools-core/src/standalone.js index bfd05cf5227ee..d65b41b478fa2 100644 --- a/packages/react-devtools-core/src/standalone.js +++ b/packages/react-devtools-core/src/standalone.js @@ -17,7 +17,6 @@ import {registerDevToolsEventLogger} from 'react-devtools-shared/src/registerDev import {Server} from 'ws'; import {join} from 'path'; import {readFileSync} from 'fs'; -import {installHook} from 'react-devtools-shared/src/hook'; import DevTools from 'react-devtools-shared/src/devtools/views/DevTools'; import {doesFilePathExist, launchEditor} from './editor'; import { @@ -29,8 +28,6 @@ import {localStorageSetItem} from 'react-devtools-shared/src/storage'; import type {FrontendBridge} from 'react-devtools-shared/src/bridge'; import type {Source} from 'react-devtools-shared/src/shared/types'; -installHook(window); - export type StatusTypes = 'server-connected' | 'devtools-connected' | 'error'; export type StatusListener = (message: string, status: StatusTypes) => void; export type OnDisconnectedCallback = () => void; @@ -371,9 +368,12 @@ function startServer( '\n;' + backendFile.toString() + '\n;' + + 'ReactDevToolsBackend.initialize();' + + '\n' + `ReactDevToolsBackend.connectToDevTools({port: ${port}, host: '${host}', useHttps: ${ useHttps ? 'true' : 'false' - }});`, + }}); + `, ); }); From 9ea5ffa9cba4869474a1d5d53e7d6c135be6adf7 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 1 Oct 2024 14:04:05 +0100 Subject: [PATCH 226/426] chore[react-devtools]: add legacy mode error message to the ignore list for tests (#31060) Without this, the console gets spammy whenever we run React DevTools tests against React 18.x, where this deprecation message was added. --- packages/react-devtools-shared/src/__tests__/setupTests.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/__tests__/setupTests.js b/packages/react-devtools-shared/src/__tests__/setupTests.js index d4afd05899a56..0a821345fcbac 100644 --- a/packages/react-devtools-shared/src/__tests__/setupTests.js +++ b/packages/react-devtools-shared/src/__tests__/setupTests.js @@ -150,7 +150,10 @@ function patchConsoleForTestingBeforeHookInstallation() { firstArg.startsWith( 'The current testing environment is not configured to support act', ) || - firstArg.startsWith('You seem to have overlapping act() calls')) + firstArg.startsWith('You seem to have overlapping act() calls') || + firstArg.startsWith( + 'ReactDOM.render is no longer supported in React 18.', + )) ) { // DevTools intentionally wraps updates with acts from both DOM and test-renderer, // since test updates are expected to impact both renderers. From 6e612587ecfca0ea2e331300635d497d54437930 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 1 Oct 2024 14:26:12 +0100 Subject: [PATCH 227/426] chore[react-devtools]: drop legacy context tests (#31059) We've dropped the support for detecting changes in legacy Contexts in https://github.com/facebook/react/pull/30896. --- .../src/__tests__/profilingCache-test.js | 688 ------------------ 1 file changed, 688 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js index 0d6d8d02a1989..fb1fa6c5f2298 100644 --- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js +++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js @@ -13,7 +13,6 @@ import type Store from 'react-devtools-shared/src/devtools/store'; import {getVersionedRenderImplementation} from './utils'; describe('ProfilingCache', () => { - let PropTypes; let React; let ReactDOM; let ReactDOMClient; @@ -34,7 +33,6 @@ describe('ProfilingCache', () => { store.collapseNodesByDefault = false; store.recordChangeDescriptions = true; - PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); @@ -309,692 +307,6 @@ describe('ProfilingCache', () => { }); }); - // @reactVersion >= 16.9 - // @reactVersion <= 18.2 - it('should record changed props/state/context/hooks for React version [16.9; 18.2] with legacy context', () => { - let instance = null; - - const ModernContext = React.createContext(0); - - class LegacyContextProvider extends React.Component { - static childContextTypes = { - count: PropTypes.number, - }; - state = {count: 0}; - getChildContext() { - return this.state; - } - render() { - instance = this; - return ( - - - - - - - ); - } - } - - const FunctionComponentWithHooks = ({count}) => { - React.useMemo(() => count, [count]); - return null; - }; - - class ModernContextConsumer extends React.Component { - static contextType = ModernContext; - render() { - return ; - } - } - - class LegacyContextConsumer extends React.Component { - static contextTypes = { - count: PropTypes.number, - }; - render() { - return ; - } - } - - utils.act(() => store.profilerStore.startProfiling()); - utils.act(() => render()); - expect(instance).not.toBeNull(); - utils.act(() => (instance: any).setState({count: 1})); - utils.act(() => render()); - utils.act(() => render()); - utils.act(() => render()); - utils.act(() => store.profilerStore.stopProfiling()); - - const rootID = store.roots[0]; - - let changeDescriptions = store.profilerStore - .getDataForRoot(rootID) - .commitData.map(commitData => commitData.changeDescriptions); - expect(changeDescriptions).toHaveLength(5); - expect(changeDescriptions[0]).toMatchInlineSnapshot(` - Map { - 2 => { - "context": null, - "didHooksChange": false, - "isFirstMount": true, - "props": null, - "state": null, - }, - 4 => { - "context": null, - "didHooksChange": false, - "isFirstMount": true, - "props": null, - "state": null, - }, - 5 => { - "context": null, - "didHooksChange": false, - "isFirstMount": true, - "props": null, - "state": null, - }, - 6 => { - "context": null, - "didHooksChange": false, - "isFirstMount": true, - "props": null, - "state": null, - }, - 7 => { - "context": null, - "didHooksChange": false, - "isFirstMount": true, - "props": null, - "state": null, - }, - } - `); - expect(changeDescriptions[1]).toMatchInlineSnapshot(` - Map { - 5 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [ - "count", - ], - "state": null, - }, - 4 => { - "context": true, - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 7 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [ - "count", - ], - "state": null, - }, - 6 => { - "context": [ - "count", - ], - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 2 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": [ - "count", - ], - }, - } - `); - expect(changeDescriptions[2]).toMatchInlineSnapshot(` - Map { - 5 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": null, - }, - 4 => { - "context": false, - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 7 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": null, - }, - 6 => { - "context": [], - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 2 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [ - "foo", - ], - "state": [], - }, - } - `); - expect(changeDescriptions[3]).toMatchInlineSnapshot(` - Map { - 5 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": null, - }, - 4 => { - "context": false, - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 7 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": null, - }, - 6 => { - "context": [], - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 2 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [ - "foo", - "bar", - ], - "state": [], - }, - } - `); - expect(changeDescriptions[4]).toMatchInlineSnapshot(` - Map { - 5 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": null, - }, - 4 => { - "context": false, - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 7 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [], - "state": null, - }, - 6 => { - "context": [], - "didHooksChange": false, - "hooks": null, - "isFirstMount": false, - "props": [], - "state": null, - }, - 2 => { - "context": null, - "didHooksChange": false, - "hooks": [], - "isFirstMount": false, - "props": [ - "bar", - ], - "state": [], - }, - } - `); - - utils.exportImportHelper(bridge, store); - - const prevChangeDescriptions = [...changeDescriptions]; - - changeDescriptions = store.profilerStore - .getDataForRoot(rootID) - .commitData.map(commitData => commitData.changeDescriptions); - expect(changeDescriptions).toHaveLength(5); - - for (let commitIndex = 0; commitIndex < 5; commitIndex++) { - expect(changeDescriptions[commitIndex]).toEqual( - prevChangeDescriptions[commitIndex], - ); - } - }); - - // @reactVersion > 18.2 - // @gate !disableLegacyContext - it('should record changed props/state/context/hooks for React version (18.2; ∞) with legacy context enabled', () => { - let instance = null; - - const ModernContext = React.createContext(0); - - class LegacyContextProvider extends React.Component { - static childContextTypes = { - count: PropTypes.number, - }; - state = {count: 0}; - getChildContext() { - return this.state; - } - render() { - instance = this; - return ( - - - - - - - ); - } - } - - const FunctionComponentWithHooks = ({count}) => { - React.useMemo(() => count, [count]); - return null; - }; - - class ModernContextConsumer extends React.Component { - static contextType = ModernContext; - render() { - return ; - } - } - - class LegacyContextConsumer extends React.Component { - static contextTypes = { - count: PropTypes.number, - }; - render() { - return ; - } - } - - utils.act(() => store.profilerStore.startProfiling()); - utils.act(() => render()); - expect(instance).not.toBeNull(); - utils.act(() => (instance: any).setState({count: 1})); - utils.act(() => render()); - utils.act(() => render()); - utils.act(() => render()); - utils.act(() => store.profilerStore.stopProfiling()); - - const rootID = store.roots[0]; - - let changeDescriptions = store.profilerStore - .getDataForRoot(rootID) - .commitData.map(commitData => commitData.changeDescriptions); - expect(changeDescriptions).toHaveLength(5); - expect(changeDescriptions[0]).toEqual( - new Map([ - [ - 2, - { - context: null, - didHooksChange: false, - isFirstMount: true, - props: null, - state: null, - }, - ], - [ - 4, - { - context: null, - didHooksChange: false, - isFirstMount: true, - props: null, - state: null, - }, - ], - [ - 5, - { - context: null, - didHooksChange: false, - isFirstMount: true, - props: null, - state: null, - }, - ], - [ - 6, - { - context: null, - didHooksChange: false, - isFirstMount: true, - props: null, - state: null, - }, - ], - [ - 7, - { - context: null, - didHooksChange: false, - isFirstMount: true, - props: null, - state: null, - }, - ], - ]), - ); - - expect(changeDescriptions[1]).toEqual( - new Map([ - [ - 5, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: ['count'], - state: null, - }, - ], - [ - 4, - { - context: true, - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 7, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: ['count'], - state: null, - }, - ], - [ - 6, - { - context: ['count'], - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 2, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: ['count'], - }, - ], - ]), - ); - - expect(changeDescriptions[2]).toEqual( - new Map([ - [ - 5, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 4, - { - context: false, - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 7, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 6, - { - context: [], - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 2, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: ['foo'], - state: [], - }, - ], - ]), - ); - - expect(changeDescriptions[3]).toEqual( - new Map([ - [ - 5, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 4, - { - context: false, - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 7, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 6, - { - context: [], - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 2, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: ['foo', 'bar'], - state: [], - }, - ], - ]), - ); - - expect(changeDescriptions[4]).toEqual( - new Map([ - [ - 5, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 4, - { - context: false, - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 7, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 6, - { - context: [], - didHooksChange: false, - hooks: null, - isFirstMount: false, - props: [], - state: null, - }, - ], - [ - 2, - { - context: null, - didHooksChange: false, - hooks: [], - isFirstMount: false, - props: ['bar'], - state: [], - }, - ], - ]), - ); - - utils.exportImportHelper(bridge, store); - - const prevChangeDescriptions = [...changeDescriptions]; - - changeDescriptions = store.profilerStore - .getDataForRoot(rootID) - .commitData.map(commitData => commitData.changeDescriptions); - expect(changeDescriptions).toHaveLength(5); - - for (let commitIndex = 0; commitIndex < 5; commitIndex++) { - expect(changeDescriptions[commitIndex]).toEqual( - prevChangeDescriptions[commitIndex], - ); - } - }); - // @reactVersion >= 18.0 it('should properly detect changed hooks', () => { const Context = React.createContext(0); From d8c90fa48d3addefe4b805ec56a3c65e4ee39127 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Tue, 1 Oct 2024 11:00:57 -0400 Subject: [PATCH 228/426] Disable infinite render loop detection (#31088) We're seeing issues with this feature internally including bugs with sibling prerendering and errors that are difficult for developers to action on. We'll turn off the feature for the time being until we can improve the stability and ergonomics. This PR does two things: - Turn off `enableInfiniteLoopDetection` everywhere while leaving it as a variant on www so we can do further experimentation. - Revert https://github.com/facebook/react/pull/31061 which was a temporary change for debugging. This brings the feature back to baseline. --- .../src/__tests__/ReactLegacyUpdates-test.js | 2 +- .../react-dom/src/__tests__/ReactUpdates-test.js | 2 +- packages/react-reconciler/src/ReactFiberWorkLoop.js | 4 ++-- packages/shared/ReactFeatureFlags.js | 12 ++++++------ packages/shared/forks/ReactFeatureFlags.native-fb.js | 2 +- .../shared/forks/ReactFeatureFlags.native-oss.js | 2 +- .../ReactFeatureFlags.test-renderer.native-fb.js | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js b/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js index 57f2acfa53465..26f56a938c551 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js @@ -1427,7 +1427,7 @@ describe('ReactLegacyUpdates', () => { } } - let limit = 105; + let limit = 55; await expect(async () => { await act(() => { ReactDOM.render(, container); diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 247a53531c659..faf4b29551350 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -1542,7 +1542,7 @@ describe('ReactUpdates', () => { } } - let limit = 105; + let limit = 55; const root = ReactDOMClient.createRoot(container); await expect(async () => { await act(() => { diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index ec5484c4b6eca..196859f6fa7ba 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -608,13 +608,13 @@ let pendingPassiveEffectsRenderEndTime: number = -0; // Profiling-only let pendingPassiveTransitions: Array | null = null; // Use these to prevent an infinite loop of nested updates -const NESTED_UPDATE_LIMIT = 100; +const NESTED_UPDATE_LIMIT = 50; let nestedUpdateCount: number = 0; let rootWithNestedUpdates: FiberRoot | null = null; let isFlushingPassiveEffects = false; let didScheduleUpdateDuringPassiveEffects = false; -const NESTED_PASSIVE_UPDATE_LIMIT = 100; +const NESTED_PASSIVE_UPDATE_LIMIT = 50; let nestedPassiveUpdateCount: number = 0; let rootWithPassiveNestedUpdates: FiberRoot | null = null; diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 9935784b533d2..cd9bfedacabd5 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -157,6 +157,12 @@ export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; +/** + * Enables a new error detection for infinite render loops from updates caused + * by setState or similar outside of the component owning the state. + */ +export const enableInfiniteRenderLoopDetection = false; + // ----------------------------------------------------------------------------- // Ready for next major. // @@ -204,12 +210,6 @@ export const enableFilterEmptyStringAttributesDOM = true; // Disabled caching behavior of `react/cache` in client runtimes. export const disableClientCache = true; -/** - * Enables a new error detection for infinite render loops from updates caused - * by setState or similar outside of the component owning the state. - */ -export const enableInfiniteRenderLoopDetection = true; - // Subtle breaking changes to JSX runtime to make it faster, like passing `ref` // as a normal prop instead of stripping it from the props object. diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 6997bf5f6805e..9dcc0f5d033ed 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -60,7 +60,7 @@ export const enableFizzExternalRuntime = true; export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = true; export const enableHalt = false; -export const enableInfiniteRenderLoopDetection = true; +export const enableInfiniteRenderLoopDetection = false; export const enableContextProfiling = false; export const enableLazyContextPropagation = true; export const enableLegacyCache = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 729cdef96d2dd..741b44daf7926 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -51,7 +51,7 @@ export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableHalt = false; export const enableHiddenSubtreeInsertionEffectCleanup = false; -export const enableInfiniteRenderLoopDetection = true; +export const enableInfiniteRenderLoopDetection = false; export const enableLazyContextPropagation = true; export const enableContextProfiling = false; export const enableLegacyCache = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index e0d946e54ec00..0cb1497eddb5f 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -41,7 +41,7 @@ export const enableFizzExternalRuntime = true; export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableHalt = false; -export const enableInfiniteRenderLoopDetection = true; +export const enableInfiniteRenderLoopDetection = false; export const enableLazyContextPropagation = true; export const enableContextProfiling = false; export const enableHiddenSubtreeInsertionEffectCleanup = true; From 99c056abb0dac0e1a15b2c85b620b72c625e065b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 1 Oct 2024 11:28:51 -0700 Subject: [PATCH 229/426] [Flight] Allow aborting encodeReply (#31106) Allow aborting encoding arguments to a Server Action if a Promise doesn't resolve. That way at least part of the arguments can be used on the receiving side. This leaves it unresolved in the stream rather than encoding an error. This should error on the receiving side when the stream closes but it doesn't right now in the Edge/Browser versions because closing happens immediately before we've had a chance to call `.then()` so the Chunks are still in pending state. This is an existing bug also in FlightClient. --- .../react-client/src/ReactFlightReplyClient.js | 17 ++++++++++++++++- .../src/client/ReactFlightDOMClientBrowser.js | 16 ++++++++++++++-- .../src/client/ReactFlightDOMClientBrowser.js | 16 ++++++++++++++-- .../src/client/ReactFlightDOMClientEdge.js | 16 ++++++++++++++-- .../src/__tests__/ReactFlightDOMReply-test.js | 16 ++++++++++++++++ .../src/client/ReactFlightDOMClientBrowser.js | 16 ++++++++++++++-- .../src/client/ReactFlightDOMClientEdge.js | 16 ++++++++++++++-- 7 files changed, 102 insertions(+), 11 deletions(-) diff --git a/packages/react-client/src/ReactFlightReplyClient.js b/packages/react-client/src/ReactFlightReplyClient.js index 35c23ed074e09..049987e39297f 100644 --- a/packages/react-client/src/ReactFlightReplyClient.js +++ b/packages/react-client/src/ReactFlightReplyClient.js @@ -185,7 +185,7 @@ export function processReply( temporaryReferences: void | TemporaryReferenceSet, resolve: (string | FormData) => void, reject: (error: mixed) => void, -): void { +): (reason: mixed) => void { let nextPartId = 1; let pendingParts = 0; let formData: null | FormData = null; @@ -841,6 +841,19 @@ export function processReply( return JSON.stringify(model, resolveToJSON); } + function abort(reason: mixed): void { + if (pendingParts > 0) { + pendingParts = 0; // Don't resolve again later. + // Resolve with what we have so far, which may have holes at this point. + // They'll error when the stream completes on the server. + if (formData === null) { + resolve(json); + } else { + resolve(formData); + } + } + } + const json = serializeModel(root, 0); if (formData === null) { @@ -854,6 +867,8 @@ export function processReply( resolve(formData); } } + + return abort; } const boundCache: WeakMap< diff --git a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js index 58a36e7023ca2..abaa793c96a71 100644 --- a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js @@ -121,12 +121,12 @@ function createFromFetch( function encodeReply( value: ReactServerValue, - options?: {temporaryReferences?: TemporaryReferenceSet}, + options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal}, ): Promise< string | URLSearchParams | FormData, > /* We don't use URLSearchParams yet but maybe */ { return new Promise((resolve, reject) => { - processReply( + const abort = processReply( value, '', options && options.temporaryReferences @@ -135,6 +135,18 @@ function encodeReply( resolve, reject, ); + if (options && options.signal) { + const signal = options.signal; + if (signal.aborted) { + abort((signal: any).reason); + } else { + const listener = () => { + abort((signal: any).reason); + signal.removeEventListener('abort', listener); + }; + signal.addEventListener('abort', listener); + } + } }); } diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js index 50a4a206ffb44..0d566a57caf5f 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js @@ -120,12 +120,12 @@ function createFromFetch( function encodeReply( value: ReactServerValue, - options?: {temporaryReferences?: TemporaryReferenceSet}, + options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal}, ): Promise< string | URLSearchParams | FormData, > /* We don't use URLSearchParams yet but maybe */ { return new Promise((resolve, reject) => { - processReply( + const abort = processReply( value, '', options && options.temporaryReferences @@ -134,6 +134,18 @@ function encodeReply( resolve, reject, ); + if (options && options.signal) { + const signal = options.signal; + if (signal.aborted) { + abort((signal: any).reason); + } else { + const listener = () => { + abort((signal: any).reason); + signal.removeEventListener('abort', listener); + }; + signal.addEventListener('abort', listener); + } + } }); } diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js index 5b3a765783a52..956e014042733 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js @@ -149,12 +149,12 @@ function createFromFetch( function encodeReply( value: ReactServerValue, - options?: {temporaryReferences?: TemporaryReferenceSet}, + options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal}, ): Promise< string | URLSearchParams | FormData, > /* We don't use URLSearchParams yet but maybe */ { return new Promise((resolve, reject) => { - processReply( + const abort = processReply( value, '', options && options.temporaryReferences @@ -163,6 +163,18 @@ function encodeReply( resolve, reject, ); + if (options && options.signal) { + const signal = options.signal; + if (signal.aborted) { + abort((signal: any).reason); + } else { + const listener = () => { + abort((signal: any).reason); + signal.removeEventListener('abort', listener); + }; + signal.addEventListener('abort', listener); + } + } }); } diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js index 30aa539e5ab5b..64a0616cacc2a 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js @@ -618,4 +618,20 @@ describe('ReactFlightDOMReply', () => { const root = await ReactServerDOMServer.decodeReply(body, webpackServerMap); expect(root.prop.obj).toBe(root.prop); }); + + it('can abort an unresolved model and get the partial result', async () => { + const promise = new Promise(r => {}); + const controller = new AbortController(); + const bodyPromise = ReactServerDOMClient.encodeReply( + {promise: promise, hello: 'world'}, + {signal: controller.signal}, + ); + controller.abort(); + + const result = await ReactServerDOMServer.decodeReply(await bodyPromise); + expect(result.hello).toBe('world'); + // TODO: await result.promise should reject at this point because the stream + // has closed but that's a bug in both ReactFlightReplyServer and ReactFlightClient. + // It just halts in this case. + }); }); diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js index 50a4a206ffb44..0d566a57caf5f 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js @@ -120,12 +120,12 @@ function createFromFetch( function encodeReply( value: ReactServerValue, - options?: {temporaryReferences?: TemporaryReferenceSet}, + options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal}, ): Promise< string | URLSearchParams | FormData, > /* We don't use URLSearchParams yet but maybe */ { return new Promise((resolve, reject) => { - processReply( + const abort = processReply( value, '', options && options.temporaryReferences @@ -134,6 +134,18 @@ function encodeReply( resolve, reject, ); + if (options && options.signal) { + const signal = options.signal; + if (signal.aborted) { + abort((signal: any).reason); + } else { + const listener = () => { + abort((signal: any).reason); + signal.removeEventListener('abort', listener); + }; + signal.addEventListener('abort', listener); + } + } }); } diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js index 5b3a765783a52..956e014042733 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js @@ -149,12 +149,12 @@ function createFromFetch( function encodeReply( value: ReactServerValue, - options?: {temporaryReferences?: TemporaryReferenceSet}, + options?: {temporaryReferences?: TemporaryReferenceSet, signal?: AbortSignal}, ): Promise< string | URLSearchParams | FormData, > /* We don't use URLSearchParams yet but maybe */ { return new Promise((resolve, reject) => { - processReply( + const abort = processReply( value, '', options && options.temporaryReferences @@ -163,6 +163,18 @@ function encodeReply( resolve, reject, ); + if (options && options.signal) { + const signal = options.signal; + if (signal.aborted) { + abort((signal: any).reason); + } else { + const listener = () => { + abort((signal: any).reason); + signal.removeEventListener('abort', listener); + }; + signal.addEventListener('abort', listener); + } + } }); } From 459fd418cfbd1f2f1be58efd8c89a0e0ecfb6d44 Mon Sep 17 00:00:00 2001 From: Timothy Yung Date: Tue, 1 Oct 2024 17:25:59 -0700 Subject: [PATCH 230/426] Define `HostInstance` type for React Native (#31101) ## Summary Creates a new `HostInstance` type for React Native, to more accurately capture the intent most developers have when using the `NativeMethods` type or `React.ElementRef>`. Since `React.ElementRef>` is typed as `React.AbstractComponent`, that means `React.ElementRef>` is equivalent to `NativeMethods` which is equivalent to `HostInstance`. ## How did you test this change? ``` $ yarn $ yarn flow fabric ``` --- .../src/ReactNativeTypes.js | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 9692a1256acff..03c03cfba0072 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -112,31 +112,32 @@ export interface INativeMethods { measure(callback: MeasureOnSuccessCallback): void; measureInWindow(callback: MeasureInWindowOnSuccessCallback): void; measureLayout( - relativeToNativeNode: number | ElementRef>, + relativeToNativeNode: number | HostInstance, onSuccess: MeasureLayoutOnSuccessCallback, onFail?: () => void, ): void; setNativeProps(nativeProps: {...}): void; } -export type NativeMethods = $ReadOnly<{| +export type NativeMethods = $ReadOnly<{ blur(): void, focus(): void, measure(callback: MeasureOnSuccessCallback): void, measureInWindow(callback: MeasureInWindowOnSuccessCallback): void, measureLayout( - relativeToNativeNode: number | ElementRef>, + relativeToNativeNode: number | HostInstance, onSuccess: MeasureLayoutOnSuccessCallback, onFail?: () => void, ): void, setNativeProps(nativeProps: {...}): void, -|}>; +}>; // This validates that INativeMethods and NativeMethods stay in sync using Flow! declare const ensureNativeMethodsAreSynced: NativeMethods; (ensureNativeMethodsAreSynced: INativeMethods); -export type HostComponent = AbstractComponent>; +export type HostInstance = NativeMethods; +export type HostComponent = AbstractComponent; type SecretInternalsType = { computeComponentStackForErrorReporting(tag: number): string, @@ -209,7 +210,7 @@ export type RenderRootOptions = { export type ReactNativeType = { findHostInstance_DEPRECATED( componentOrHandle: ?(ElementRef | number), - ): ?ElementRef>, + ): ?HostInstance, findNodeHandle( componentOrHandle: ?(ElementRef | number), ): ?number, @@ -218,14 +219,11 @@ export type ReactNativeType = { child: PublicInstance | HostComponent, ): boolean, dispatchCommand( - handle: ElementRef>, + handle: HostInstance, command: string, args: Array, ): void, - sendAccessibilityEvent( - handle: ElementRef>, - eventType: string, - ): void, + sendAccessibilityEvent(handle: HostInstance, eventType: string): void, render( element: MixedElement, containerTag: number, @@ -247,20 +245,17 @@ type PublicTextInstance = mixed; export type ReactFabricType = { findHostInstance_DEPRECATED( componentOrHandle: ?(ElementRef | number), - ): ?ElementRef>, + ): ?HostInstance, findNodeHandle( componentOrHandle: ?(ElementRef | number), ): ?number, dispatchCommand( - handle: ElementRef>, + handle: HostInstance, command: string, args: Array, ): void, isChildPublicInstance(parent: PublicInstance, child: PublicInstance): boolean, - sendAccessibilityEvent( - handle: ElementRef>, - eventType: string, - ): void, + sendAccessibilityEvent(handle: HostInstance, eventType: string): void, render( element: MixedElement, containerTag: number, From 0751fac747452af8c0494900b4afa7c56ee7b32c Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Wed, 2 Oct 2024 12:53:57 -0400 Subject: [PATCH 231/426] [compiler] Optional chaining for dependencies (HIR rewrite) Adds HIR version of `PropagateScopeDeps` to handle optional chaining. Internally, this improves memoization on ~4% of compiled files (internal links: [1](https://www.internalfb.com/intern/paste/P1610406497/)) Summarizing the changes in this PR. 1. `CollectOptionalChainDependencies` recursively traverses optional blocks down to the base. From the base, we build up a set of `baseIdentifier.propertyA?.propertyB` mappings. The tricky bit here is that optional blocks sometimes reference other optional blocks that are *not* part of the same chain e.g. a(c?.d)?.d. See code + comments in `traverseOptionalBlock` for how we avoid concatenating unrelated blocks. 2. Adding optional chains into non-null object calculation. (Note that marking `a?.b` as 'non-null' means that `a?.b.c` is safe to evaluate, *not* `(a?.b).c`. Happy to rename this / reword comments accordingly if there's a better term) This pass is split into two stages. (1) collecting non-null objects by block and (2) propagating non-null objects across blocks. The only significant change here was to (2). We add an extra reduce step `X=Reduce(Union(X, Intersect(X_neighbors)))` to merge optional and non-optional nodes (e.g. nonNulls=`{a, a?.b}` reduces to `{a, a.b}`) 3. Adding optional chains into dependency calculation. This was the trickiest. We need to take the "maximal" property chain as a dependency. Prior to this PR, we avoided taking subpaths e.g. `a.b` of `a.b.c` as dependencies by only visiting non-PropertyLoad/LoadLocal instructions. This effectively only recorded the property-path at site-of-use. Unfortunately, this *quite* doesn't work for optional chains for a few reasons: - We would need to skip relevant `StoreLocal`/`Branch terminal` instructions (but only those within optional blocks that have been successfully read). - Given an optional chain, either (1) only a subpath or (2) the entire path can be represented as a PropertyLoad. We cannot directly add the last hoistable optional-block as a dependency as MethodCalls are an edge case e.g. given a?.b.c(), we should depend on `a?.b`, not `a?.b.c` This means that we add its dependency at either the innermost unhoistable optional-block or when encountering it within its phi-join. 4. Handle optional chains in DeriveMinimalDependenciesHIR. This was also a bit tricky to formulate. Ideally, we would avoid a 2^3 case join (cond | uncond cfg, optional | not optional load, access | dependency). This PR attempts to simplify by building two trees 1. First add each hoistable path into a tree containing `Optional | NonOptional` nodes. 2. Then add each dependency into another tree containing `Optional | NonOptional`, `Access | Dependency` nodes, truncating the dependency at the earliest non-hoistable node (i.e. non-matching pair when walking the hoistable tree) ghstack-source-id: a2170f26280dfbf65a4893d8a658f863a0fd0c88 Pull Request resolved: https://github.com/facebook/react/pull/31037 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 128 +++++- .../HIR/CollectOptionalChainDependencies.ts | 382 ++++++++++++++++++ .../src/HIR/DeriveMinimalDependenciesHIR.ts | 367 ++++++++++------- .../src/HIR/HIR.ts | 1 + .../src/HIR/PropagateScopeDependenciesHIR.ts | 111 +++-- .../src/Utils/utils.ts | 24 ++ ...equential-optional-chain-nonnull.expect.md | 71 ++++ ...infer-sequential-optional-chain-nonnull.ts | 20 + .../compiler/nested-optional-chains.expect.md | 229 +++++++++++ .../compiler/nested-optional-chains.ts | 91 +++++ ...al-member-expression-as-memo-dep.expect.md | 96 +++-- .../optional-member-expression-as-memo-dep.js | 25 +- ...ptional-member-expression-single.expect.md | 82 ++-- .../optional-member-expression-single.js | 20 +- ...-optional-call-chain-in-optional.expect.md | 2 +- ...al-member-expression-as-memo-dep.expect.md | 32 -- ...-optional-member-expression-as-memo-dep.js | 7 - ...ession-single-with-unconditional.expect.md | 42 -- ...ptional-member-expression-single.expect.md | 39 -- ....todo-optional-member-expression-single.js | 10 - ...equential-optional-chain-nonnull.expect.md | 74 ++++ ...infer-sequential-optional-chain-nonnull.ts | 22 + .../nested-optional-chains.expect.md | 232 +++++++++++ .../nested-optional-chains.ts | 93 +++++ ...al-member-expression-as-memo-dep.expect.md | 98 +++++ .../optional-member-expression-as-memo-dep.js | 24 ++ ...ession-single-with-unconditional.expect.md | 62 +++ ...r-expression-single-with-unconditional.js} | 0 ...ptional-member-expression-single.expect.md | 91 +++++ .../optional-member-expression-single.js | 22 + ...properties-inside-optional-chain.expect.md | 4 +- .../conditional-member-expr.expect.md | 4 +- .../memberexpr-join-optional-chain.expect.md | 4 +- .../memberexpr-join-optional-chain2.expect.md | 21 +- ...e-uncond-optional-chain-and-cond.expect.md | 72 ++++ .../merge-uncond-optional-chain-and-cond.ts | 22 + ...epro-scope-missing-mutable-range.expect.md | 4 +- 37 files changed, 2221 insertions(+), 407 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.ts delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.js delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single-with-unconditional.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/{error.todo-optional-member-expression-single-with-unconditional.js => optional-member-expression-single-with-unconditional.js} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index cb778c329226b..3603416ee6887 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -1,6 +1,12 @@ import {CompilerError} from '../CompilerError'; import {inRange} from '../ReactiveScopes/InferReactiveScopeVariables'; -import {Set_intersect, Set_union, getOrInsertDefault} from '../Utils/utils'; +import { + Set_equal, + Set_filter, + Set_intersect, + Set_union, + getOrInsertDefault, +} from '../Utils/utils'; import { BasicBlock, BlockId, @@ -15,9 +21,9 @@ import { } from './HIR'; /** - * Helper function for `PropagateScopeDependencies`. - * Uses control flow graph analysis to determine which `Identifier`s can - * be assumed to be non-null objects, on a per-block basis. + * Helper function for `PropagateScopeDependencies`. Uses control flow graph + * analysis to determine which `Identifier`s can be assumed to be non-null + * objects, on a per-block basis. * * Here is an example: * ```js @@ -42,15 +48,16 @@ import { * } * ``` * - * Note that we currently do NOT account for mutable / declaration range - * when doing the CFG-based traversal, producing results that are technically + * Note that we currently do NOT account for mutable / declaration range when + * doing the CFG-based traversal, producing results that are technically * incorrect but filtered by PropagateScopeDeps (which only takes dependencies * on constructed value -- i.e. a scope's dependencies must have mutable ranges * ending earlier than the scope start). * - * Take this example, this function will infer x.foo.bar as non-nullable for bb0, - * via the intersection of bb1 & bb2 which in turn comes from bb3. This is technically - * incorrect bb0 is before / during x's mutable range. + * Take this example, this function will infer x.foo.bar as non-nullable for + * bb0, via the intersection of bb1 & bb2 which in turn comes from bb3. This is + * technically incorrect bb0 is before / during x's mutable range. + * ``` * bb0: * const x = ...; * if cond then bb1 else bb2 @@ -62,15 +69,30 @@ import { * goto bb3: * bb3: * x.foo.bar + * ``` + * + * @param fn + * @param temporaries sidemap of identifier -> baseObject.a.b paths. Does not + * contain optional chains. + * @param hoistableFromOptionals sidemap of optionalBlock -> baseObject?.a + * optional paths for which it's safe to evaluate non-optional loads (see + * CollectOptionalChainDependencies). + * @returns */ export function collectHoistablePropertyLoads( fn: HIRFunction, temporaries: ReadonlyMap, + hoistableFromOptionals: ReadonlyMap, ): ReadonlyMap { const registry = new PropertyPathRegistry(); - const nodes = collectNonNullsInBlocks(fn, temporaries, registry); - propagateNonNull(fn, nodes); + const nodes = collectNonNullsInBlocks( + fn, + temporaries, + hoistableFromOptionals, + registry, + ); + propagateNonNull(fn, nodes, registry); const nodesKeyedByScopeId = new Map(); for (const [_, block] of fn.body.blocks) { @@ -96,17 +118,21 @@ export type BlockInfo = { */ type RootNode = { properties: Map; + optionalProperties: Map; parent: null; // Recorded to make later computations simpler fullPath: ReactiveScopeDependency; + hasOptional: boolean; root: IdentifierId; }; type PropertyPathNode = | { properties: Map; + optionalProperties: Map; parent: PropertyPathNode; fullPath: ReactiveScopeDependency; + hasOptional: boolean; } | RootNode; @@ -124,10 +150,12 @@ class PropertyPathRegistry { rootNode = { root: identifier.id, properties: new Map(), + optionalProperties: new Map(), fullPath: { identifier, path: [], }, + hasOptional: false, parent: null, }; this.roots.set(identifier.id, rootNode); @@ -139,23 +167,20 @@ class PropertyPathRegistry { parent: PropertyPathNode, entry: DependencyPathEntry, ): PropertyPathNode { - if (entry.optional) { - CompilerError.throwTodo({ - reason: 'handle optional nodes', - loc: GeneratedSource, - }); - } - let child = parent.properties.get(entry.property); + const map = entry.optional ? parent.optionalProperties : parent.properties; + let child = map.get(entry.property); if (child == null) { child = { properties: new Map(), + optionalProperties: new Map(), parent: parent, fullPath: { identifier: parent.fullPath.identifier, path: parent.fullPath.path.concat(entry), }, + hasOptional: parent.hasOptional || entry.optional, }; - parent.properties.set(entry.property, child); + map.set(entry.property, child); } return child; } @@ -216,6 +241,7 @@ function addNonNullPropertyPath( function collectNonNullsInBlocks( fn: HIRFunction, temporaries: ReadonlyMap, + hoistableFromOptionals: ReadonlyMap, registry: PropertyPathRegistry, ): ReadonlyMap { /** @@ -252,6 +278,13 @@ function collectNonNullsInBlocks( const assumedNonNullObjects = new Set( knownNonNullIdentifiers, ); + + const maybeOptionalChain = hoistableFromOptionals.get(block.id); + if (maybeOptionalChain != null) { + assumedNonNullObjects.add( + registry.getOrCreateProperty(maybeOptionalChain), + ); + } for (const instr of block.instructions) { if (instr.value.kind === 'PropertyLoad') { const source = temporaries.get(instr.value.object.identifier.id) ?? { @@ -303,6 +336,7 @@ function collectNonNullsInBlocks( function propagateNonNull( fn: HIRFunction, nodes: ReadonlyMap, + registry: PropertyPathRegistry, ): void { const blockSuccessors = new Map>(); const terminalPreds = new Set(); @@ -388,10 +422,17 @@ function propagateNonNull( const prevObjects = assertNonNull(nodes.get(nodeId)).assumedNonNullObjects; const mergedObjects = Set_union(prevObjects, neighborAccesses); + reduceMaybeOptionalChains(mergedObjects, registry); assertNonNull(nodes.get(nodeId)).assumedNonNullObjects = mergedObjects; traversalState.set(nodeId, 'done'); - changed ||= prevObjects.size !== mergedObjects.size; + /** + * Note that it's not sufficient to compare set sizes since + * reduceMaybeOptionalChains may replace optional-chain loads with + * unconditional loads. This could in turn change `assumedNonNullObjects` of + * downstream blocks and backedges. + */ + changed ||= !Set_equal(prevObjects, mergedObjects); return changed; } const traversalState = new Map(); @@ -440,3 +481,50 @@ export function assertNonNull, U>( }); return value; } + +/** + * Any two optional chains with different operations . vs ?. but the same set of + * property strings paths de-duplicates. + * + * Intuitively: given ?.b, we know to be either hoistable or not. + * If unconditional reads from are hoistable, we can replace all + * ?.PROPERTY_STRING subpaths with .PROPERTY_STRING + */ +function reduceMaybeOptionalChains( + nodes: Set, + registry: PropertyPathRegistry, +): void { + let optionalChainNodes = Set_filter(nodes, n => n.hasOptional); + if (optionalChainNodes.size === 0) { + return; + } + let changed: boolean; + do { + changed = false; + + for (const original of optionalChainNodes) { + let {identifier, path: origPath} = original.fullPath; + let currNode: PropertyPathNode = + registry.getOrCreateIdentifier(identifier); + for (let i = 0; i < origPath.length; i++) { + const entry = origPath[i]; + // If the base is known to be non-null, replace with a non-optional load + const nextEntry: DependencyPathEntry = + entry.optional && nodes.has(currNode) + ? {property: entry.property, optional: false} + : entry; + currNode = PropertyPathRegistry.getOrCreatePropertyEntry( + currNode, + nextEntry, + ); + } + if (currNode !== original) { + changed = true; + optionalChainNodes.delete(original); + optionalChainNodes.add(currNode); + nodes.delete(original); + nodes.add(currNode); + } + } + } while (changed); +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts new file mode 100644 index 0000000000000..453294784246f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts @@ -0,0 +1,382 @@ +import {CompilerError} from '..'; +import {assertNonNull} from './CollectHoistablePropertyLoads'; +import { + BlockId, + BasicBlock, + InstructionId, + IdentifierId, + ReactiveScopeDependency, + BranchTerminal, + TInstruction, + PropertyLoad, + StoreLocal, + GotoVariant, + TBasicBlock, + OptionalTerminal, + HIRFunction, + DependencyPathEntry, +} from './HIR'; +import {printIdentifier} from './PrintHIR'; + +export function collectOptionalChainSidemap( + fn: HIRFunction, +): OptionalChainSidemap { + const context: OptionalTraversalContext = { + blocks: fn.body.blocks, + seenOptionals: new Set(), + processedInstrsInOptional: new Set(), + temporariesReadInOptional: new Map(), + hoistableObjects: new Map(), + }; + for (const [_, block] of fn.body.blocks) { + if ( + block.terminal.kind === 'optional' && + !context.seenOptionals.has(block.id) + ) { + traverseOptionalBlock( + block as TBasicBlock, + context, + null, + ); + } + } + + return { + temporariesReadInOptional: context.temporariesReadInOptional, + processedInstrsInOptional: context.processedInstrsInOptional, + hoistableObjects: context.hoistableObjects, + }; +} +export type OptionalChainSidemap = { + /** + * Stores the correct property mapping (e.g. `a?.b` instead of `a.b`) for + * dependency calculation. Note that we currently do not store anything on + * outer phi nodes. + */ + temporariesReadInOptional: ReadonlyMap; + /** + * Records instructions (PropertyLoads, StoreLocals, and test terminals) + * processed in this pass. When extracting dependencies in + * PropagateScopeDependencies, these instructions are skipped. + * + * E.g. given a?.b + * ``` + * bb0 + * $0 = LoadLocal 'a' + * test $0 then=bb1 <- Avoid adding dependencies from these instructions, as + * bb1 the sidemap produced by readOptionalBlock already maps + * $1 = PropertyLoad $0.'b' <- $1 and $2 back to a?.b. Instead, we want to add a?.b + * StoreLocal $2 = $1 <- as a dependency when $1 or $2 are later used in either + * - an unhoistable expression within an outer optional + * block e.g. MethodCall + * - a phi node (if the entire optional value is hoistable) + * ``` + * + * Note that mapping blockIds to their evaluated dependency path does not + * work, since values produced by inner optional chains may be referenced in + * outer ones + * ``` + * a?.b.c() + * -> + * bb0 + * $0 = LoadLocal 'a' + * test $0 then=bb1 + * bb1 + * $1 = PropertyLoad $0.'b' + * StoreLocal $2 = $1 + * goto bb2 + * bb2 + * test $2 then=bb3 + * bb3: + * $3 = PropertyLoad $2.'c' + * StoreLocal $4 = $3 + * goto bb4 + * bb4 + * test $4 then=bb5 + * bb5: + * $5 = MethodCall $2.$4() <--- here, we want to take a dep on $2 and $4! + * ``` + */ + processedInstrsInOptional: ReadonlySet; + /** + * Records optional chains for which we can safely evaluate non-optional + * PropertyLoads. e.g. given `a?.b.c`, we can evaluate any load from `a?.b` at + * the optional terminal in bb1. + * ```js + * bb1: + * ... + * Optional optional=false test=bb2 fallth=... + * bb2: + * Optional optional=true test=bb3 fallth=... + * ... + * ``` + */ + hoistableObjects: ReadonlyMap; +}; + +type OptionalTraversalContext = { + blocks: ReadonlyMap; + + // Track optional blocks to avoid outer calls into nested optionals + seenOptionals: Set; + + processedInstrsInOptional: Set; + temporariesReadInOptional: Map; + hoistableObjects: Map; +}; + +/** + * Match the consequent and alternate blocks of an optional. + * @returns propertyload computed by the consequent block, or null if the + * consequent block is not a simple PropertyLoad. + */ +function matchOptionalTestBlock( + terminal: BranchTerminal, + blocks: ReadonlyMap, +): { + consequentId: IdentifierId; + property: string; + propertyId: IdentifierId; + storeLocalInstrId: InstructionId; + consequentGoto: BlockId; +} | null { + const consequentBlock = assertNonNull(blocks.get(terminal.consequent)); + if ( + consequentBlock.instructions.length === 2 && + consequentBlock.instructions[0].value.kind === 'PropertyLoad' && + consequentBlock.instructions[1].value.kind === 'StoreLocal' + ) { + const propertyLoad: TInstruction = consequentBlock + .instructions[0] as TInstruction; + const storeLocal: StoreLocal = consequentBlock.instructions[1].value; + const storeLocalInstrId = consequentBlock.instructions[1].id; + CompilerError.invariant( + propertyLoad.value.object.identifier.id === terminal.test.identifier.id, + { + reason: + '[OptionalChainDeps] Inconsistent optional chaining property load', + description: `Test=${printIdentifier(terminal.test.identifier)} PropertyLoad base=${printIdentifier(propertyLoad.value.object.identifier)}`, + loc: propertyLoad.loc, + }, + ); + + CompilerError.invariant( + storeLocal.value.identifier.id === propertyLoad.lvalue.identifier.id, + { + reason: '[OptionalChainDeps] Unexpected storeLocal', + loc: propertyLoad.loc, + }, + ); + if ( + consequentBlock.terminal.kind !== 'goto' || + consequentBlock.terminal.variant !== GotoVariant.Break + ) { + return null; + } + const alternate = assertNonNull(blocks.get(terminal.alternate)); + + CompilerError.invariant( + alternate.instructions.length === 2 && + alternate.instructions[0].value.kind === 'Primitive' && + alternate.instructions[1].value.kind === 'StoreLocal', + { + reason: 'Unexpected alternate structure', + loc: terminal.loc, + }, + ); + + return { + consequentId: storeLocal.lvalue.place.identifier.id, + property: propertyLoad.value.property, + propertyId: propertyLoad.lvalue.identifier.id, + storeLocalInstrId, + consequentGoto: consequentBlock.terminal.block, + }; + } + return null; +} + +/** + * Traverse into the optional block and all transitively referenced blocks to + * collect sidemaps of optional chain dependencies. + * + * @returns the IdentifierId representing the optional block if the block and + * all transitively referenced optional blocks precisely represent a chain of + * property loads. If any part of the optional chain is not hoistable, returns + * null. + */ +function traverseOptionalBlock( + optional: TBasicBlock, + context: OptionalTraversalContext, + outerAlternate: BlockId | null, +): IdentifierId | null { + context.seenOptionals.add(optional.id); + const maybeTest = context.blocks.get(optional.terminal.test)!; + let test: BranchTerminal; + let baseObject: ReactiveScopeDependency; + if (maybeTest.terminal.kind === 'branch') { + CompilerError.invariant(optional.terminal.optional, { + reason: '[OptionalChainDeps] Expect base case to be always optional', + loc: optional.terminal.loc, + }); + /** + * Optional base expressions are currently within value blocks which cannot + * be interrupted by scope boundaries. As such, the only dependencies we can + * hoist out of optional chains are property load chains with no intervening + * instructions. + * + * Ideally, we would be able to flatten base instructions out of optional + * blocks, but this would require changes to HIR. + * + * For now, only match base expressions that are straightforward + * PropertyLoad chains + */ + if ( + maybeTest.instructions.length === 0 || + maybeTest.instructions[0].value.kind !== 'LoadLocal' + ) { + return null; + } + const path: Array = []; + for (let i = 1; i < maybeTest.instructions.length; i++) { + const instrVal = maybeTest.instructions[i].value; + const prevInstr = maybeTest.instructions[i - 1]; + if ( + instrVal.kind === 'PropertyLoad' && + instrVal.object.identifier.id === prevInstr.lvalue.identifier.id + ) { + path.push({property: instrVal.property, optional: false}); + } else { + return null; + } + } + CompilerError.invariant( + maybeTest.terminal.test.identifier.id === + maybeTest.instructions.at(-1)!.lvalue.identifier.id, + { + reason: '[OptionalChainDeps] Unexpected test expression', + loc: maybeTest.terminal.loc, + }, + ); + baseObject = { + identifier: maybeTest.instructions[0].value.place.identifier, + path, + }; + test = maybeTest.terminal; + } else if (maybeTest.terminal.kind === 'optional') { + /** + * This is either + * - ?.property (optional=true) + * - .property (optional=false) + * - + * - a optional base block with a separate nested optional-chain (e.g. a(c?.d)?.d) + */ + const testBlock = context.blocks.get(maybeTest.terminal.fallthrough)!; + if (testBlock!.terminal.kind !== 'branch') { + /** + * Fallthrough of the inner optional should be a block with no + * instructions, terminating with Test($) + */ + CompilerError.throwTodo({ + reason: `Unexpected terminal kind \`${testBlock.terminal.kind}\` for optional fallthrough block`, + loc: maybeTest.terminal.loc, + }); + } + /** + * Recurse into inner optional blocks to collect inner optional-chain + * expressions, regardless of whether we can match the outer one to a + * PropertyLoad. + */ + const innerOptional = traverseOptionalBlock( + maybeTest as TBasicBlock, + context, + testBlock.terminal.alternate, + ); + if (innerOptional == null) { + return null; + } + + /** + * Check that the inner optional is part of the same optional-chain as the + * outer one. This is not guaranteed, e.g. given a(c?.d)?.d + * ``` + * bb0: + * Optional test=bb1 + * bb1: + * $0 = LoadLocal a <-- part 1 of the outer optional-chaining base + * Optional test=bb2 fallth=bb5 <-- start of optional chain for c?.d + * bb2: + * ... (optional chain for c?.d) + * ... + * bb5: + * $1 = phi(c.d, undefined) <-- part 2 (continuation) of the outer optional-base + * $2 = Call $0($1) + * Branch $2 ... + * ``` + */ + if (testBlock.terminal.test.identifier.id !== innerOptional) { + return null; + } + + if (!optional.terminal.optional) { + /** + * If this is an non-optional load participating in an optional chain + * (e.g. loading the `c` property in `a?.b.c`), record that PropertyLoads + * from the inner optional value are hoistable. + */ + context.hoistableObjects.set( + optional.id, + assertNonNull(context.temporariesReadInOptional.get(innerOptional)), + ); + } + baseObject = assertNonNull( + context.temporariesReadInOptional.get(innerOptional), + ); + test = testBlock.terminal; + } else { + return null; + } + + if (test.alternate === outerAlternate) { + CompilerError.invariant(optional.instructions.length === 0, { + reason: + '[OptionalChainDeps] Unexpected instructions an inner optional block. ' + + 'This indicates that the compiler may be incorrectly concatenating two unrelated optional chains', + loc: optional.terminal.loc, + }); + } + const matchConsequentResult = matchOptionalTestBlock(test, context.blocks); + if (!matchConsequentResult) { + // Optional chain consequent is not hoistable e.g. a?.[computed()] + return null; + } + CompilerError.invariant( + matchConsequentResult.consequentGoto === optional.terminal.fallthrough, + { + reason: '[OptionalChainDeps] Unexpected optional goto-fallthrough', + description: `${matchConsequentResult.consequentGoto} != ${optional.terminal.fallthrough}`, + loc: optional.terminal.loc, + }, + ); + const load = { + identifier: baseObject.identifier, + path: [ + ...baseObject.path, + { + property: matchConsequentResult.property, + optional: optional.terminal.optional, + }, + ], + }; + context.processedInstrsInOptional.add( + matchConsequentResult.storeLocalInstrId, + ); + context.processedInstrsInOptional.add(test.id); + context.temporariesReadInOptional.set( + matchConsequentResult.consequentId, + load, + ); + context.temporariesReadInOptional.set(matchConsequentResult.propertyId, load); + return matchConsequentResult.consequentId; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts index f2bb0b31f05c9..f5567b3e536d1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/DeriveMinimalDependenciesHIR.ts @@ -6,97 +6,173 @@ */ import {CompilerError} from '../CompilerError'; -import {GeneratedSource, Identifier, ReactiveScopeDependency} from '../HIR'; +import { + DependencyPathEntry, + GeneratedSource, + Identifier, + ReactiveScopeDependency, +} from '../HIR'; import {printIdentifier} from '../HIR/PrintHIR'; import {ReactiveScopePropertyDependency} from '../ReactiveScopes/DeriveMinimalDependencies'; -const ENABLE_DEBUG_INVARIANTS = true; - /** * Simpler fork of DeriveMinimalDependencies, see PropagateScopeDependenciesHIR * for detailed explanation. */ export class ReactiveScopeDependencyTreeHIR { - #roots: Map = new Map(); + /** + * Paths from which we can hoist PropertyLoads. If an `identifier`, + * `identifier.path`, or `identifier?.path` is in this map, it is safe to + * evaluate (non-optional) PropertyLoads from. + */ + #hoistableObjects: Map = new Map(); + #deps: Map = new Map(); + + /** + * @param hoistableObjects a set of paths from which we can safely evaluate + * PropertyLoads. Note that we expect these to not contain duplicates (e.g. + * both `a?.b` and `a.b`) only because CollectHoistablePropertyLoads merges + * duplicates when traversing the CFG. + */ + constructor(hoistableObjects: Iterable) { + for (const {path, identifier} of hoistableObjects) { + let currNode = ReactiveScopeDependencyTreeHIR.#getOrCreateRoot( + identifier, + this.#hoistableObjects, + path.length > 0 && path[0].optional ? 'Optional' : 'NonNull', + ); - #getOrCreateRoot( + for (let i = 0; i < path.length; i++) { + const prevAccessType = currNode.properties.get( + path[i].property, + )?.accessType; + const accessType = + i + 1 < path.length && path[i + 1].optional ? 'Optional' : 'NonNull'; + CompilerError.invariant( + prevAccessType == null || prevAccessType === accessType, + { + reason: 'Conflicting access types', + loc: GeneratedSource, + }, + ); + let nextNode = currNode.properties.get(path[i].property); + if (nextNode == null) { + nextNode = { + properties: new Map(), + accessType, + }; + currNode.properties.set(path[i].property, nextNode); + } + currNode = nextNode; + } + } + } + + static #getOrCreateRoot( identifier: Identifier, - accessType: PropertyAccessType, - ): DependencyNode { + roots: Map>, + defaultAccessType: T, + ): TreeNode { // roots can always be accessed unconditionally in JS - let rootNode = this.#roots.get(identifier); + let rootNode = roots.get(identifier); if (rootNode === undefined) { rootNode = { properties: new Map(), - accessType, + accessType: defaultAccessType, }; - this.#roots.set(identifier, rootNode); + roots.set(identifier, rootNode); } return rootNode; } + /** + * Join a dependency with `#hoistableObjects` to record the hoistable + * dependency. This effectively truncates @param dep to its maximal + * safe-to-evaluate subpath + */ addDependency(dep: ReactiveScopePropertyDependency): void { - const {path} = dep; - let currNode = this.#getOrCreateRoot(dep.identifier, MIN_ACCESS_TYPE); - - const accessType = PropertyAccessType.Access; - - currNode.accessType = merge(currNode.accessType, accessType); - - for (const property of path) { - // all properties read 'on the way' to a dependency are marked as 'access' - let currChild = makeOrMergeProperty( - currNode, - property.property, - accessType, - ); - currNode = currChild; - } - - /* - * If this property does not have a conditional path (i.e. a.b.c), the - * final property node should be marked as an conditional/unconditional - * `dependency` as based on control flow. - */ - currNode.accessType = merge( - currNode.accessType, - PropertyAccessType.Dependency, + const {identifier, path} = dep; + let depCursor = ReactiveScopeDependencyTreeHIR.#getOrCreateRoot( + identifier, + this.#deps, + PropertyAccessType.UnconditionalAccess, ); - } + /** + * hoistableCursor is null if depCursor is not an object we can hoist + * property reads from otherwise, it represents the same node in the + * hoistable / cfg-informed tree + */ + let hoistableCursor: HoistableNode | undefined = + this.#hoistableObjects.get(identifier); - markNodesNonNull(dep: ReactiveScopePropertyDependency): void { - const accessType = PropertyAccessType.NonNullAccess; - let currNode = this.#roots.get(dep.identifier); + // All properties read 'on the way' to a dependency are marked as 'access' + for (const entry of path) { + let nextHoistableCursor: HoistableNode | undefined; + let nextDepCursor: DependencyNode; + if (entry.optional) { + /** + * No need to check the access type since we can match both optional or non-optionals + * in the hoistable + * e.g. a?.b is hoistable if a.b is hoistable + */ + if (hoistableCursor != null) { + nextHoistableCursor = hoistableCursor?.properties.get(entry.property); + } - let cursor = 0; - while (currNode != null && cursor < dep.path.length) { - currNode.accessType = merge(currNode.accessType, accessType); - currNode = currNode.properties.get(dep.path[cursor++].property); - } - if (currNode != null) { - currNode.accessType = merge(currNode.accessType, accessType); + let accessType; + if ( + hoistableCursor != null && + hoistableCursor.accessType === 'NonNull' + ) { + /** + * For an optional chain dep `a?.b`: if the hoistable tree only + * contains `a`, we can keep either `a?.b` or 'a.b' as a dependency. + * (note that we currently do the latter for perf) + */ + accessType = PropertyAccessType.UnconditionalAccess; + } else { + /** + * Given that it's safe to evaluate `depCursor` and optional load + * never throws, it's also safe to evaluate `depCursor?.entry` + */ + accessType = PropertyAccessType.OptionalAccess; + } + nextDepCursor = makeOrMergeProperty( + depCursor, + entry.property, + accessType, + ); + } else if ( + hoistableCursor != null && + hoistableCursor.accessType === 'NonNull' + ) { + nextHoistableCursor = hoistableCursor.properties.get(entry.property); + nextDepCursor = makeOrMergeProperty( + depCursor, + entry.property, + PropertyAccessType.UnconditionalAccess, + ); + } else { + /** + * Break to truncate the dependency on its first non-optional entry that PropertyLoads are not hoistable from + */ + break; + } + depCursor = nextDepCursor; + hoistableCursor = nextHoistableCursor; } + // mark the final node as a dependency + depCursor.accessType = merge( + depCursor.accessType, + PropertyAccessType.OptionalDependency, + ); } - /** - * Derive a set of minimal dependencies that are safe to - * access unconditionally (with respect to nullthrows behavior) - */ deriveMinimalDependencies(): Set { const results = new Set(); - for (const [rootId, rootNode] of this.#roots.entries()) { - if (ENABLE_DEBUG_INVARIANTS) { - assertWellFormedTree(rootNode); - } - const deps = deriveMinimalDependenciesInSubtree(rootNode, []); - - for (const dep of deps) { - results.add({ - identifier: rootId, - path: dep.path.map(s => ({property: s, optional: false})), - }); - } + for (const [rootId, rootNode] of this.#deps.entries()) { + collectMinimalDependenciesInSubtree(rootNode, rootId, [], results); } return results; @@ -110,7 +186,7 @@ export class ReactiveScopeDependencyTreeHIR { printDeps(includeAccesses: boolean): string { let res: Array> = []; - for (const [rootId, rootNode] of this.#roots.entries()) { + for (const [rootId, rootNode] of this.#deps.entries()) { const rootResults = printSubtree(rootNode, includeAccesses).map( result => `${printIdentifier(rootId)}.${result}`, ); @@ -118,31 +194,64 @@ export class ReactiveScopeDependencyTreeHIR { } return res.flat().join('\n'); } + + static debug(roots: Map>): string { + const buf: Array = [`tree() [`]; + for (const [rootId, rootNode] of roots) { + buf.push(`${printIdentifier(rootId)} (${rootNode.accessType}):`); + this.#debugImpl(buf, rootNode, 1); + } + buf.push(']'); + return buf.length > 2 ? buf.join('\n') : buf.join(''); + } + + static #debugImpl( + buf: Array, + node: TreeNode, + depth: number = 0, + ): void { + for (const [property, childNode] of node.properties) { + buf.push(`${' '.repeat(depth)}.${property} (${childNode.accessType}):`); + this.#debugImpl(buf, childNode, depth + 1); + } + } } +/* + * Enum representing the access type of single property on a parent object. + * We distinguish on two independent axes: + * Optional / Unconditional: + * - whether this property is an optional load (within an optional chain) + * Access / Dependency: + * - Access: this property is read on the path of a dependency. We do not + * need to track change variables for accessed properties. Tracking accesses + * helps Forget do more granular dependency tracking. + * - Dependency: this property is read as a dependency and we must track changes + * to it for correctness. + * ```javascript + * // props.a is a dependency here and must be tracked + * deps: {props.a, props.a.b} ---> minimalDeps: {props.a} + * // props.a is just an access here and does not need to be tracked + * deps: {props.a.b} ---> minimalDeps: {props.a.b} + * ``` + */ enum PropertyAccessType { - Access = 'Access', - NonNullAccess = 'NonNullAccess', - Dependency = 'Dependency', - NonNullDependency = 'NonNullDependency', + OptionalAccess = 'OptionalAccess', + UnconditionalAccess = 'UnconditionalAccess', + OptionalDependency = 'OptionalDependency', + UnconditionalDependency = 'UnconditionalDependency', } -const MIN_ACCESS_TYPE = PropertyAccessType.Access; -/** - * "NonNull" means that PropertyReads from a node are side-effect free, - * as the node is (1) immutable and (2) has unconditional propertyloads - * somewhere in the cfg. - */ -function isNonNull(access: PropertyAccessType): boolean { +function isOptional(access: PropertyAccessType): boolean { return ( - access === PropertyAccessType.NonNullAccess || - access === PropertyAccessType.NonNullDependency + access === PropertyAccessType.OptionalAccess || + access === PropertyAccessType.OptionalDependency ); } function isDependency(access: PropertyAccessType): boolean { return ( - access === PropertyAccessType.Dependency || - access === PropertyAccessType.NonNullDependency + access === PropertyAccessType.OptionalDependency || + access === PropertyAccessType.UnconditionalDependency ); } @@ -150,92 +259,70 @@ function merge( access1: PropertyAccessType, access2: PropertyAccessType, ): PropertyAccessType { - const resultisNonNull = isNonNull(access1) || isNonNull(access2); + const resultIsUnconditional = !(isOptional(access1) && isOptional(access2)); const resultIsDependency = isDependency(access1) || isDependency(access2); /* * Straightforward merge. * This can be represented as bitwise OR, but is written out for readability * - * Observe that `NonNullAccess | Dependency` produces an + * Observe that `UnconditionalAccess | ConditionalDependency` produces an * unconditionally accessed conditional dependency. We currently use these * as we use unconditional dependencies. (i.e. to codegen change variables) */ - if (resultisNonNull) { + if (resultIsUnconditional) { if (resultIsDependency) { - return PropertyAccessType.NonNullDependency; + return PropertyAccessType.UnconditionalDependency; } else { - return PropertyAccessType.NonNullAccess; + return PropertyAccessType.UnconditionalAccess; } } else { + // result is optional if (resultIsDependency) { - return PropertyAccessType.Dependency; + return PropertyAccessType.OptionalDependency; } else { - return PropertyAccessType.Access; + return PropertyAccessType.OptionalAccess; } } } -type DependencyNode = { - properties: Map; - accessType: PropertyAccessType; +type TreeNode = { + properties: Map>; + accessType: T; }; +type HoistableNode = TreeNode<'Optional' | 'NonNull'>; +type DependencyNode = TreeNode; -type ReduceResultNode = { - path: Array; -}; - -function assertWellFormedTree(node: DependencyNode): void { - let nonNullInChildren = false; - for (const childNode of node.properties.values()) { - assertWellFormedTree(childNode); - nonNullInChildren ||= isNonNull(childNode.accessType); - } - if (nonNullInChildren) { - CompilerError.invariant(isNonNull(node.accessType), { - reason: - '[DeriveMinimialDependencies] Not well formed tree, unexpected non-null node', - description: node.accessType, - loc: GeneratedSource, - }); - } -} - -function deriveMinimalDependenciesInSubtree( +/** + * TODO: this is directly pasted from DeriveMinimalDependencies. Since we no + * longer have conditionally accessed nodes, we can simplify + * + * Recursively calculates minimal dependencies in a subtree. + * @param node DependencyNode representing a dependency subtree. + * @returns a minimal list of dependencies in this subtree. + */ +function collectMinimalDependenciesInSubtree( node: DependencyNode, - path: Array, -): Array { + rootIdentifier: Identifier, + path: Array, + results: Set, +): void { if (isDependency(node.accessType)) { - /** - * If this node is a dependency, we truncate the subtree - * and return this node. e.g. deps=[`obj.a`, `obj.a.b`] - * reduces to deps=[`obj.a`] - */ - return [{path}]; + results.add({identifier: rootIdentifier, path}); } else { - if (isNonNull(node.accessType)) { - /* - * Only recurse into subtree dependencies if this node - * is known to be non-null. - */ - const result: Array = []; - for (const [childName, childNode] of node.properties) { - result.push( - ...deriveMinimalDependenciesInSubtree(childNode, [ - ...path, - childName, - ]), - ); - } - return result; - } else { - /* - * This only occurs when this subtree contains a dependency, - * but this node is potentially nullish. As we currently - * don't record optional property paths as scope dependencies, - * we truncate and record this node as a dependency. - */ - return [{path}]; + for (const [childName, childNode] of node.properties) { + collectMinimalDependenciesInSubtree( + childNode, + rootIdentifier, + [ + ...path, + { + property: childName, + optional: isOptional(childNode.accessType), + }, + ], + results, + ); } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 615ec18feb962..873082bdbeaa0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -367,6 +367,7 @@ export type BasicBlock = { preds: Set; phis: Set; }; +export type TBasicBlock = BasicBlock & {terminal: T}; /* * Terminal nodes generally represent statements that affect control flow, such as diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index 1fe218c352818..a7346e0e6b984 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -17,10 +17,7 @@ import { areEqualPaths, IdentifierId, } from './HIR'; -import { - BlockInfo, - collectHoistablePropertyLoads, -} from './CollectHoistablePropertyLoads'; +import {collectHoistablePropertyLoads} from './CollectHoistablePropertyLoads'; import { ScopeBlockTraversal, eachInstructionOperand, @@ -32,37 +29,61 @@ import {Stack, empty} from '../Utils/Stack'; import {CompilerError} from '../CompilerError'; import {Iterable_some} from '../Utils/utils'; import {ReactiveScopeDependencyTreeHIR} from './DeriveMinimalDependenciesHIR'; +import {collectOptionalChainSidemap} from './CollectOptionalChainDependencies'; export function propagateScopeDependenciesHIR(fn: HIRFunction): void { const usedOutsideDeclaringScope = findTemporariesUsedOutsideDeclaringScope(fn); const temporaries = collectTemporariesSidemap(fn, usedOutsideDeclaringScope); + const { + temporariesReadInOptional, + processedInstrsInOptional, + hoistableObjects, + } = collectOptionalChainSidemap(fn); - const hoistablePropertyLoads = collectHoistablePropertyLoads(fn, temporaries); + const hoistablePropertyLoads = collectHoistablePropertyLoads( + fn, + temporaries, + hoistableObjects, + ); const scopeDeps = collectDependencies( fn, usedOutsideDeclaringScope, - temporaries, + new Map([...temporaries, ...temporariesReadInOptional]), + processedInstrsInOptional, ); /** * Derive the minimal set of hoistable dependencies for each scope. */ for (const [scope, deps] of scopeDeps) { - const tree = new ReactiveScopeDependencyTreeHIR(); + if (deps.length === 0) { + continue; + } /** - * Step 1: Add every dependency used by this scope (e.g. `a.b.c`) + * Step 1: Find hoistable accesses, given the basic block in which the scope + * begins. + */ + const hoistables = hoistablePropertyLoads.get(scope.id); + CompilerError.invariant(hoistables != null, { + reason: '[PropagateScopeDependencies] Scope not found in tracked blocks', + loc: GeneratedSource, + }); + /** + * Step 2: Calculate hoistable dependencies. */ + const tree = new ReactiveScopeDependencyTreeHIR( + [...hoistables.assumedNonNullObjects].map(o => o.fullPath), + ); for (const dep of deps) { tree.addDependency({...dep}); } + /** - * Step 2: Mark hoistable dependencies, given the basic block in - * which the scope begins. + * Step 3: Reduce dependencies to a minimal set. */ - recordHoistablePropertyReads(hoistablePropertyLoads, scope.id, tree); const candidates = tree.deriveMinimalDependencies(); for (const candidateDep of candidates) { if ( @@ -201,7 +222,12 @@ function collectTemporariesSidemap( ); if (value.kind === 'PropertyLoad' && !usedOutside) { - const property = getProperty(value.object, value.property, temporaries); + const property = getProperty( + value.object, + value.property, + false, + temporaries, + ); temporaries.set(lvalue.identifier.id, property); } else if ( value.kind === 'LoadLocal' && @@ -222,6 +248,7 @@ function collectTemporariesSidemap( function getProperty( object: Place, propertyName: string, + optional: boolean, temporaries: ReadonlyMap, ): ReactiveScopeDependency { /* @@ -253,15 +280,12 @@ function getProperty( if (resolvedDependency == null) { property = { identifier: object.identifier, - path: [{property: propertyName, optional: false}], + path: [{property: propertyName, optional}], }; } else { property = { identifier: resolvedDependency.identifier, - path: [ - ...resolvedDependency.path, - {property: propertyName, optional: false}, - ], + path: [...resolvedDependency.path, {property: propertyName, optional}], }; } return property; @@ -409,8 +433,13 @@ class Context { ); } - visitProperty(object: Place, property: string): void { - const nextDependency = getProperty(object, property, this.#temporaries); + visitProperty(object: Place, property: string, optional: boolean): void { + const nextDependency = getProperty( + object, + property, + optional, + this.#temporaries, + ); this.visitDependency(nextDependency); } @@ -489,7 +518,7 @@ function handleInstruction(instr: Instruction, context: Context): void { } } else if (value.kind === 'PropertyLoad') { if (context.isUsedOutsideDeclaringScope(lvalue)) { - context.visitProperty(value.object, value.property); + context.visitProperty(value.object, value.property, false); } } else if (value.kind === 'StoreLocal') { context.visitOperand(value.value); @@ -544,6 +573,7 @@ function collectDependencies( fn: HIRFunction, usedOutsideDeclaringScope: ReadonlySet, temporaries: ReadonlyMap, + processedInstrsInOptional: ReadonlySet, ): Map> { const context = new Context(usedOutsideDeclaringScope, temporaries); @@ -572,33 +602,26 @@ function collectDependencies( context.exitScope(scopeBlockInfo.scope, scopeBlockInfo?.pruned); } + // Record referenced optional chains in phis + for (const phi of block.phis) { + for (const operand of phi.operands) { + const maybeOptionalChain = temporaries.get(operand[1].id); + if (maybeOptionalChain) { + context.visitDependency(maybeOptionalChain); + } + } + } for (const instr of block.instructions) { - handleInstruction(instr, context); + if (!processedInstrsInOptional.has(instr.id)) { + handleInstruction(instr, context); + } } - for (const place of eachTerminalOperand(block.terminal)) { - context.visitOperand(place); + + if (!processedInstrsInOptional.has(block.terminal.id)) { + for (const place of eachTerminalOperand(block.terminal)) { + context.visitOperand(place); + } } } return context.deps; } - -/** - * Compute the set of hoistable property reads. - */ -function recordHoistablePropertyReads( - nodes: ReadonlyMap, - scopeId: ScopeId, - tree: ReactiveScopeDependencyTreeHIR, -): void { - const node = nodes.get(scopeId); - CompilerError.invariant(node != null, { - reason: '[PropagateScopeDependencies] Scope not found in tracked blocks', - loc: GeneratedSource, - }); - - for (const item of node.assumedNonNullObjects) { - tree.markNodesNonNull({ - ...item.fullPath, - }); - } -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/Utils/utils.ts b/compiler/packages/babel-plugin-react-compiler/src/Utils/utils.ts index 6b813d597560c..aa91c48b1b0db 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Utils/utils.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Utils/utils.ts @@ -82,6 +82,17 @@ export function getOrInsertDefault( return defaultValue; } } +export function Set_equal(a: ReadonlySet, b: ReadonlySet): boolean { + if (a.size !== b.size) { + return false; + } + for (const item of a) { + if (!b.has(item)) { + return false; + } + } + return true; +} export function Set_union(a: ReadonlySet, b: ReadonlySet): Set { const union = new Set(a); @@ -128,6 +139,19 @@ export function nonNull, U>( return value != null; } +export function Set_filter( + source: ReadonlySet, + fn: (arg: T) => boolean, +): Set { + const result = new Set(); + for (const entry of source) { + if (fn(entry)) { + result.add(entry); + } + } + return result; +} + export function hasNode( input: NodePath, ): input is NodePath> { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md new file mode 100644 index 0000000000000..31e2cadf9f7db --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md @@ -0,0 +1,71 @@ + +## Input + +```javascript +function useFoo({a}) { + let x = []; + x.push(a?.b.c?.d.e); + x.push(a.b?.c.d?.e); + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: null}, + {a: {}}, + {a: {b: {c: {d: {e: 42}}}}}, + {a: {b: {c: {d: {e: 43}}}}}, + {a: {b: {c: {d: {e: undefined}}}}}, + {a: {b: undefined}}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +function useFoo(t0) { + const $ = _c(2); + const { a } = t0; + let x; + if ($[0] !== a.b.c.d) { + x = []; + x.push(a?.b.c?.d.e); + x.push(a.b?.c.d?.e); + $[0] = a.b.c.d; + $[1] = x; + } else { + x = $[1]; + } + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [ + { a: null }, + { a: null }, + { a: {} }, + { a: { b: { c: { d: { e: 42 } } } } }, + { a: { b: { c: { d: { e: 43 } } } } }, + { a: { b: { c: { d: { e: undefined } } } } }, + { a: { b: undefined } }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +[[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] +[42,42] +[43,43] +[null,null] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.ts new file mode 100644 index 0000000000000..479048085e925 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.ts @@ -0,0 +1,20 @@ +function useFoo({a}) { + let x = []; + x.push(a?.b.c?.d.e); + x.push(a.b?.c.d?.e); + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: null}, + {a: {}}, + {a: {b: {c: {d: {e: 42}}}}}, + {a: {b: {c: {d: {e: 43}}}}}, + {a: {b: {c: {d: {e: undefined}}}}}, + {a: {b: undefined}}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md new file mode 100644 index 0000000000000..0acf33b2ed87f --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md @@ -0,0 +1,229 @@ + +## Input + +```javascript +import {identity} from 'shared-runtime'; + +/** + * identity(...)?.toString() is the outer optional, and prop?.value is the inner + * one. + * Note that prop?. + */ +function useFoo({ + prop1, + prop2, + prop3, + prop4, + prop5, + prop6, +}: { + prop1: null | {value: number}; + prop2: null | {inner: {value: number}}; + prop3: null | {fn: (val: any) => NonNullable}; + prop4: null | {inner: {value: number}}; + prop5: null | {fn: (val: any) => NonNullable}; + prop6: null | {inner: {value: number}}; +}) { + // prop1?.value should be hoisted as the dependency of x + const x = identity(prop1?.value)?.toString(); + + // prop2?.inner.value should be hoisted as the dependency of y + const y = identity(prop2?.inner.value)?.toString(); + + // prop3 and prop4?.inner should be hoisted as the dependency of z + const z = prop3?.fn(prop4?.inner.value).toString(); + + // prop5 and prop6?.inner should be hoisted as the dependency of zz + const zz = prop5?.fn(prop6?.inner.value)?.toString(); + return [x, y, z, zz]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + ], + sequentialRenders: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: 4}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: undefined}}, + prop3: {fn: identity}, + prop4: {inner: {value: undefined}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {}, + prop3: {fn: identity}, + prop4: {}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { identity } from "shared-runtime"; + +/** + * identity(...)?.toString() is the outer optional, and prop?.value is the inner + * one. + * Note that prop?. + */ +function useFoo(t0) { + const $ = _c(15); + const { prop1, prop2, prop3, prop4, prop5, prop6 } = t0; + let t1; + if ($[0] !== prop1?.value) { + t1 = identity(prop1?.value)?.toString(); + $[0] = prop1?.value; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let t2; + if ($[2] !== prop2?.inner) { + t2 = identity(prop2?.inner.value)?.toString(); + $[2] = prop2?.inner; + $[3] = t2; + } else { + t2 = $[3]; + } + const y = t2; + let t3; + if ($[4] !== prop3 || $[5] !== prop4) { + t3 = prop3?.fn(prop4?.inner.value).toString(); + $[4] = prop3; + $[5] = prop4; + $[6] = t3; + } else { + t3 = $[6]; + } + const z = t3; + let t4; + if ($[7] !== prop5 || $[8] !== prop6) { + t4 = prop5?.fn(prop6?.inner.value)?.toString(); + $[7] = prop5; + $[8] = prop6; + $[9] = t4; + } else { + t4 = $[9]; + } + const zz = t4; + let t5; + if ($[10] !== x || $[11] !== y || $[12] !== z || $[13] !== zz) { + t5 = [x, y, z, zz]; + $[10] = x; + $[11] = y; + $[12] = z; + $[13] = zz; + $[14] = t5; + } else { + t5 = $[14]; + } + return t5; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + ], + + sequentialRenders: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + { + prop1: { value: 2 }, + prop2: { inner: { value: 3 } }, + prop3: { fn: identity }, + prop4: { inner: { value: 4 } }, + prop5: { fn: identity }, + prop6: { inner: { value: 4 } }, + }, + { + prop1: { value: 2 }, + prop2: { inner: { value: 3 } }, + prop3: { fn: identity }, + prop4: { inner: { value: 4 } }, + prop5: { fn: identity }, + prop6: { inner: { value: undefined } }, + }, + { + prop1: { value: 2 }, + prop2: { inner: { value: undefined } }, + prop3: { fn: identity }, + prop4: { inner: { value: undefined } }, + prop5: { fn: identity }, + prop6: { inner: { value: undefined } }, + }, + { + prop1: { value: 2 }, + prop2: {}, + prop3: { fn: identity }, + prop4: {}, + prop5: { fn: identity }, + prop6: { inner: { value: undefined } }, + }, + ], +}; + +``` + +### Eval output +(kind: ok) [null,null,null,null] +["2","3","4","4"] +["2","3","4",null] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'toString') ]] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'value') ]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.ts new file mode 100644 index 0000000000000..d00cb4fee6983 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.ts @@ -0,0 +1,91 @@ +import {identity} from 'shared-runtime'; + +/** + * identity(...)?.toString() is the outer optional, and prop?.value is the inner + * one. + * Note that prop?. + */ +function useFoo({ + prop1, + prop2, + prop3, + prop4, + prop5, + prop6, +}: { + prop1: null | {value: number}; + prop2: null | {inner: {value: number}}; + prop3: null | {fn: (val: any) => NonNullable}; + prop4: null | {inner: {value: number}}; + prop5: null | {fn: (val: any) => NonNullable}; + prop6: null | {inner: {value: number}}; +}) { + // prop1?.value should be hoisted as the dependency of x + const x = identity(prop1?.value)?.toString(); + + // prop2?.inner.value should be hoisted as the dependency of y + const y = identity(prop2?.inner.value)?.toString(); + + // prop3 and prop4?.inner should be hoisted as the dependency of z + const z = prop3?.fn(prop4?.inner.value).toString(); + + // prop5 and prop6?.inner should be hoisted as the dependency of zz + const zz = prop5?.fn(prop6?.inner.value)?.toString(); + return [x, y, z, zz]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + ], + sequentialRenders: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: 4}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: undefined}}, + prop3: {fn: identity}, + prop4: {inner: {value: undefined}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {}, + prop3: {fn: identity}, + prop4: {}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md index c34b79a848ba8..77875f789d7a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md @@ -3,12 +3,29 @@ ```javascript // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -function Component(props) { +import {identity, ValidateMemoization} from 'shared-runtime'; +import {useMemo} from 'react'; + +function Component({arg}) { const data = useMemo(() => { - return props?.items.edges?.nodes.map(); - }, [props?.items.edges?.nodes]); - return ; + return arg?.items.edges?.nodes.map(identity); + }, [arg?.items.edges?.nodes]); + return ( + + ); } +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: null}], + sequentialRenders: [ + {arg: null}, + {arg: null}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + ], +}; ``` @@ -16,33 +33,66 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -function Component(props) { - const $ = _c(4); +import { identity, ValidateMemoization } from "shared-runtime"; +import { useMemo } from "react"; + +function Component(t0) { + const $ = _c(7); + const { arg } = t0; - props?.items.edges?.nodes; - let t0; + arg?.items.edges?.nodes; let t1; - if ($[0] !== props?.items.edges?.nodes) { - t1 = props?.items.edges?.nodes.map(); - $[0] = props?.items.edges?.nodes; - $[1] = t1; + let t2; + if ($[0] !== arg?.items.edges?.nodes) { + t2 = arg?.items.edges?.nodes.map(identity); + $[0] = arg?.items.edges?.nodes; + $[1] = t2; } else { - t1 = $[1]; + t2 = $[1]; } - t0 = t1; - const data = t0; - let t2; - if ($[2] !== data) { - t2 = ; - $[2] = data; - $[3] = t2; + t1 = t2; + const data = t1; + + const t3 = arg?.items.edges?.nodes; + let t4; + if ($[2] !== t3) { + t4 = [t3]; + $[2] = t3; + $[3] = t4; + } else { + t4 = $[3]; + } + let t5; + if ($[4] !== t4 || $[5] !== data) { + t5 = ; + $[4] = t4; + $[5] = data; + $[6] = t5; } else { - t2 = $[3]; + t5 = $[6]; } - return t2; + return t5; } +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arg: null }], + sequentialRenders: [ + { arg: null }, + { arg: null }, + { arg: { items: { edges: null } } }, + { arg: { items: { edges: null } } }, + { arg: { items: { edges: { nodes: [1, 2, "hello"] } } } }, + { arg: { items: { edges: { nodes: [1, 2, "hello"] } } } }, + ], +}; + ``` ### Eval output -(kind: exception) Fixture not implemented \ No newline at end of file +(kind: ok)
{"inputs":[null]}
+
{"inputs":[null]}
+
{"inputs":[null]}
+
{"inputs":[null]}
+
{"inputs":[[1,2,"hello"]],"output":[1,2,"hello"]}
+
{"inputs":[[1,2,"hello"]],"output":[1,2,"hello"]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js index d82d36b547970..73f0f4d421a4c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.js @@ -1,7 +1,24 @@ // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -function Component(props) { +import {identity, ValidateMemoization} from 'shared-runtime'; +import {useMemo} from 'react'; + +function Component({arg}) { const data = useMemo(() => { - return props?.items.edges?.nodes.map(); - }, [props?.items.edges?.nodes]); - return ; + return arg?.items.edges?.nodes.map(identity); + }, [arg?.items.edges?.nodes]); + return ( + + ); } +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: null}], + sequentialRenders: [ + {arg: null}, + {arg: null}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md index a4cf6d767d1c3..6e44a97b456b3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md @@ -4,15 +4,27 @@ ```javascript // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { +import {useMemo} from 'react'; +function Component({arg}) { const data = useMemo(() => { const x = []; - x.push(props?.items); + x.push(arg?.items); return x; - }, [props?.items]); - return ; + }, [arg?.items]); + return ; } +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: {items: 2}}], + sequentialRenders: [ + {arg: {items: 2}}, + {arg: {items: 2}}, + {arg: null}, + {arg: null}, + ], +}; + ``` ## Code @@ -20,44 +32,60 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies import { ValidateMemoization } from "shared-runtime"; -function Component(props) { +import { useMemo } from "react"; +function Component(t0) { const $ = _c(7); + const { arg } = t0; - props?.items; - let t0; + arg?.items; + let t1; let x; - if ($[0] !== props?.items) { + if ($[0] !== arg?.items) { x = []; - x.push(props?.items); - $[0] = props?.items; + x.push(arg?.items); + $[0] = arg?.items; $[1] = x; } else { x = $[1]; } - t0 = x; - const data = t0; - const t1 = props?.items; - let t2; - if ($[2] !== t1) { - t2 = [t1]; - $[2] = t1; - $[3] = t2; + t1 = x; + const data = t1; + const t2 = arg?.items; + let t3; + if ($[2] !== t2) { + t3 = [t2]; + $[2] = t2; + $[3] = t3; } else { - t2 = $[3]; + t3 = $[3]; } - let t3; - if ($[4] !== t2 || $[5] !== data) { - t3 = ; - $[4] = t2; + let t4; + if ($[4] !== t3 || $[5] !== data) { + t4 = ; + $[4] = t3; $[5] = data; - $[6] = t3; + $[6] = t4; } else { - t3 = $[6]; + t4 = $[6]; } - return t3; + return t4; } +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arg: { items: 2 } }], + sequentialRenders: [ + { arg: { items: 2 } }, + { arg: { items: 2 } }, + { arg: null }, + { arg: null }, + ], +}; + ``` ### Eval output -(kind: exception) Fixture not implemented \ No newline at end of file +(kind: ok)
{"inputs":[2],"output":[2]}
+
{"inputs":[2],"output":[2]}
+
{"inputs":[null],"output":[null]}
+
{"inputs":[null],"output":[null]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js index 5750d7af3a0e0..62ac31dd6d1b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.js @@ -1,10 +1,22 @@ // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { +import {useMemo} from 'react'; +function Component({arg}) { const data = useMemo(() => { const x = []; - x.push(props?.items); + x.push(arg?.items); return x; - }, [props?.items]); - return ; + }, [arg?.items]); + return ; } + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: {items: 2}}], + sequentialRenders: [ + {arg: {items: 2}}, + {arg: {items: 2}}, + {arg: null}, + {arg: null}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md index 8b52187920cbe..e0196bdc1945c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-call-chain-in-optional.expect.md @@ -26,7 +26,7 @@ export const FIXTURE_ENTRYPONT = { 2 | function useFoo(props: {value: {x: string; y: string} | null}) { 3 | const value = props.value; > 4 | return createArray(value?.x, value?.y)?.join(', '); - | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional test block (4:4) + | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional fallthrough block (4:4) 5 | } 6 | 7 | function createArray(...args: Array): Array { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.expect.md deleted file mode 100644 index e885982310117..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.expect.md +++ /dev/null @@ -1,32 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR -function Component(props) { - const data = useMemo(() => { - return props?.items.edges?.nodes.map(); - }, [props?.items.edges?.nodes]); - return ; -} - -``` - - -## Error - -``` - 1 | // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR - 2 | function Component(props) { -> 3 | const data = useMemo(() => { - | ^^^^^^^ -> 4 | return props?.items.edges?.nodes.map(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 5 | }, [props?.items.edges?.nodes]); - | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (3:5) - 6 | return ; - 7 | } - 8 | -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.js deleted file mode 100644 index 6ff87d0c46329..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-as-memo-dep.js +++ /dev/null @@ -1,7 +0,0 @@ -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR -function Component(props) { - const data = useMemo(() => { - return props?.items.edges?.nodes.map(); - }, [props?.items.edges?.nodes]); - return ; -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single-with-unconditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single-with-unconditional.expect.md deleted file mode 100644 index 3559b2bd58b28..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single-with-unconditional.expect.md +++ /dev/null @@ -1,42 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR -import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { - const data = useMemo(() => { - const x = []; - x.push(props?.items); - x.push(props.items); - return x; - }, [props.items]); - return ; -} - -``` - - -## Error - -``` - 2 | import {ValidateMemoization} from 'shared-runtime'; - 3 | function Component(props) { -> 4 | const data = useMemo(() => { - | ^^^^^^^ -> 5 | const x = []; - | ^^^^^^^^^^^^^^^^^ -> 6 | x.push(props?.items); - | ^^^^^^^^^^^^^^^^^ -> 7 | x.push(props.items); - | ^^^^^^^^^^^^^^^^^ -> 8 | return x; - | ^^^^^^^^^^^^^^^^^ -> 9 | }, [props.items]); - | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (4:9) - 10 | return ; - 11 | } - 12 | -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.expect.md deleted file mode 100644 index 429f168836b82..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.expect.md +++ /dev/null @@ -1,39 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR -import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { - const data = useMemo(() => { - const x = []; - x.push(props?.items); - return x; - }, [props?.items]); - return ; -} - -``` - - -## Error - -``` - 2 | import {ValidateMemoization} from 'shared-runtime'; - 3 | function Component(props) { -> 4 | const data = useMemo(() => { - | ^^^^^^^ -> 5 | const x = []; - | ^^^^^^^^^^^^^^^^^ -> 6 | x.push(props?.items); - | ^^^^^^^^^^^^^^^^^ -> 7 | return x; - | ^^^^^^^^^^^^^^^^^ -> 8 | }, [props?.items]); - | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (4:8) - 9 | return ; - 10 | } - 11 | -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.js deleted file mode 100644 index 535a0ce074419..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single.js +++ /dev/null @@ -1,10 +0,0 @@ -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR -import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { - const data = useMemo(() => { - const x = []; - x.push(props?.items); - return x; - }, [props?.items]); - return ; -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.expect.md new file mode 100644 index 0000000000000..757ad2666d962 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.expect.md @@ -0,0 +1,74 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +function useFoo({a}) { + let x = []; + x.push(a?.b.c?.d.e); + x.push(a.b?.c.d?.e); + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: null}, + {a: {}}, + {a: {b: {c: {d: {e: 42}}}}}, + {a: {b: {c: {d: {e: 43}}}}}, + {a: {b: {c: {d: {e: undefined}}}}}, + {a: {b: undefined}}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +function useFoo(t0) { + const $ = _c(2); + const { a } = t0; + let x; + if ($[0] !== a.b.c.d.e) { + x = []; + x.push(a?.b.c?.d.e); + x.push(a.b?.c.d?.e); + $[0] = a.b.c.d.e; + $[1] = x; + } else { + x = $[1]; + } + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [ + { a: null }, + { a: null }, + { a: {} }, + { a: { b: { c: { d: { e: 42 } } } } }, + { a: { b: { c: { d: { e: 43 } } } } }, + { a: { b: { c: { d: { e: undefined } } } } }, + { a: { b: undefined } }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +[[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] +[42,42] +[43,43] +[null,null] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.ts new file mode 100644 index 0000000000000..750e422861c3a --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/infer-sequential-optional-chain-nonnull.ts @@ -0,0 +1,22 @@ +// @enablePropagateDepsInHIR + +function useFoo({a}) { + let x = []; + x.push(a?.b.c?.d.e); + x.push(a.b?.c.d?.e); + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: null}, + {a: {}}, + {a: {b: {c: {d: {e: 42}}}}}, + {a: {b: {c: {d: {e: 43}}}}}, + {a: {b: {c: {d: {e: undefined}}}}}, + {a: {b: undefined}}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.expect.md new file mode 100644 index 0000000000000..56b987c677e20 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.expect.md @@ -0,0 +1,232 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {identity} from 'shared-runtime'; + +/** + * identity(...)?.toString() is the outer optional, and prop?.value is the inner + * one. + * Note that prop?. + */ +function useFoo({ + prop1, + prop2, + prop3, + prop4, + prop5, + prop6, +}: { + prop1: null | {value: number}; + prop2: null | {inner: {value: number}}; + prop3: null | {fn: (val: any) => NonNullable}; + prop4: null | {inner: {value: number}}; + prop5: null | {fn: (val: any) => NonNullable}; + prop6: null | {inner: {value: number}}; +}) { + // prop1?.value should be hoisted as the dependency of x + const x = identity(prop1?.value)?.toString(); + + // prop2?.inner.value should be hoisted as the dependency of y + const y = identity(prop2?.inner.value)?.toString(); + + // prop3 and prop4?.inner should be hoisted as the dependency of z + const z = prop3?.fn(prop4?.inner.value).toString(); + + // prop5 and prop6?.inner should be hoisted as the dependency of zz + const zz = prop5?.fn(prop6?.inner.value)?.toString(); + return [x, y, z, zz]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + ], + sequentialRenders: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: 4}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: undefined}}, + prop3: {fn: identity}, + prop4: {inner: {value: undefined}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {}, + prop3: {fn: identity}, + prop4: {}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { identity } from "shared-runtime"; + +/** + * identity(...)?.toString() is the outer optional, and prop?.value is the inner + * one. + * Note that prop?. + */ +function useFoo(t0) { + const $ = _c(15); + const { prop1, prop2, prop3, prop4, prop5, prop6 } = t0; + let t1; + if ($[0] !== prop1?.value) { + t1 = identity(prop1?.value)?.toString(); + $[0] = prop1?.value; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let t2; + if ($[2] !== prop2?.inner.value) { + t2 = identity(prop2?.inner.value)?.toString(); + $[2] = prop2?.inner.value; + $[3] = t2; + } else { + t2 = $[3]; + } + const y = t2; + let t3; + if ($[4] !== prop3 || $[5] !== prop4?.inner) { + t3 = prop3?.fn(prop4?.inner.value).toString(); + $[4] = prop3; + $[5] = prop4?.inner; + $[6] = t3; + } else { + t3 = $[6]; + } + const z = t3; + let t4; + if ($[7] !== prop5 || $[8] !== prop6?.inner) { + t4 = prop5?.fn(prop6?.inner.value)?.toString(); + $[7] = prop5; + $[8] = prop6?.inner; + $[9] = t4; + } else { + t4 = $[9]; + } + const zz = t4; + let t5; + if ($[10] !== x || $[11] !== y || $[12] !== z || $[13] !== zz) { + t5 = [x, y, z, zz]; + $[10] = x; + $[11] = y; + $[12] = z; + $[13] = zz; + $[14] = t5; + } else { + t5 = $[14]; + } + return t5; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + ], + + sequentialRenders: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + { + prop1: { value: 2 }, + prop2: { inner: { value: 3 } }, + prop3: { fn: identity }, + prop4: { inner: { value: 4 } }, + prop5: { fn: identity }, + prop6: { inner: { value: 4 } }, + }, + { + prop1: { value: 2 }, + prop2: { inner: { value: 3 } }, + prop3: { fn: identity }, + prop4: { inner: { value: 4 } }, + prop5: { fn: identity }, + prop6: { inner: { value: undefined } }, + }, + { + prop1: { value: 2 }, + prop2: { inner: { value: undefined } }, + prop3: { fn: identity }, + prop4: { inner: { value: undefined } }, + prop5: { fn: identity }, + prop6: { inner: { value: undefined } }, + }, + { + prop1: { value: 2 }, + prop2: {}, + prop3: { fn: identity }, + prop4: {}, + prop5: { fn: identity }, + prop6: { inner: { value: undefined } }, + }, + ], +}; + +``` + +### Eval output +(kind: ok) [null,null,null,null] +["2","3","4","4"] +["2","3","4",null] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'toString') ]] +[[ (exception in render) TypeError: Cannot read properties of undefined (reading 'value') ]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.ts new file mode 100644 index 0000000000000..48f3b2de2a72b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/nested-optional-chains.ts @@ -0,0 +1,93 @@ +// @enablePropagateDepsInHIR + +import {identity} from 'shared-runtime'; + +/** + * identity(...)?.toString() is the outer optional, and prop?.value is the inner + * one. + * Note that prop?. + */ +function useFoo({ + prop1, + prop2, + prop3, + prop4, + prop5, + prop6, +}: { + prop1: null | {value: number}; + prop2: null | {inner: {value: number}}; + prop3: null | {fn: (val: any) => NonNullable}; + prop4: null | {inner: {value: number}}; + prop5: null | {fn: (val: any) => NonNullable}; + prop6: null | {inner: {value: number}}; +}) { + // prop1?.value should be hoisted as the dependency of x + const x = identity(prop1?.value)?.toString(); + + // prop2?.inner.value should be hoisted as the dependency of y + const y = identity(prop2?.inner.value)?.toString(); + + // prop3 and prop4?.inner should be hoisted as the dependency of z + const z = prop3?.fn(prop4?.inner.value).toString(); + + // prop5 and prop6?.inner should be hoisted as the dependency of zz + const zz = prop5?.fn(prop6?.inner.value)?.toString(); + return [x, y, z, zz]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + ], + sequentialRenders: [ + { + prop1: null, + prop2: null, + prop3: null, + prop4: null, + prop5: null, + prop6: null, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: 4}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: 3}}, + prop3: {fn: identity}, + prop4: {inner: {value: 4}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {inner: {value: undefined}}, + prop3: {fn: identity}, + prop4: {inner: {value: undefined}}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + { + prop1: {value: 2}, + prop2: {}, + prop3: {fn: identity}, + prop4: {}, + prop5: {fn: identity}, + prop6: {inner: {value: undefined}}, + }, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md new file mode 100644 index 0000000000000..d0486cd8c29fd --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md @@ -0,0 +1,98 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import {identity, ValidateMemoization} from 'shared-runtime'; +import {useMemo} from 'react'; + +function Component({arg}) { + const data = useMemo(() => { + return arg?.items.edges?.nodes.map(identity); + }, [arg?.items.edges?.nodes]); + return ( + + ); +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: null}], + sequentialRenders: [ + {arg: null}, + {arg: null}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import { identity, ValidateMemoization } from "shared-runtime"; +import { useMemo } from "react"; + +function Component(t0) { + const $ = _c(7); + const { arg } = t0; + + arg?.items.edges?.nodes; + let t1; + let t2; + if ($[0] !== arg?.items.edges?.nodes) { + t2 = arg?.items.edges?.nodes.map(identity); + $[0] = arg?.items.edges?.nodes; + $[1] = t2; + } else { + t2 = $[1]; + } + t1 = t2; + const data = t1; + + const t3 = arg?.items.edges?.nodes; + let t4; + if ($[2] !== t3) { + t4 = [t3]; + $[2] = t3; + $[3] = t4; + } else { + t4 = $[3]; + } + let t5; + if ($[4] !== t4 || $[5] !== data) { + t5 = ; + $[4] = t4; + $[5] = data; + $[6] = t5; + } else { + t5 = $[6]; + } + return t5; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arg: null }], + sequentialRenders: [ + { arg: null }, + { arg: null }, + { arg: { items: { edges: null } } }, + { arg: { items: { edges: null } } }, + { arg: { items: { edges: { nodes: [1, 2, "hello"] } } } }, + { arg: { items: { edges: { nodes: [1, 2, "hello"] } } } }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"inputs":[null]}
+
{"inputs":[null]}
+
{"inputs":[null]}
+
{"inputs":[null]}
+
{"inputs":[[1,2,"hello"]],"output":[1,2,"hello"]}
+
{"inputs":[[1,2,"hello"]],"output":[1,2,"hello"]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.js new file mode 100644 index 0000000000000..d248c472f5aa7 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.js @@ -0,0 +1,24 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import {identity, ValidateMemoization} from 'shared-runtime'; +import {useMemo} from 'react'; + +function Component({arg}) { + const data = useMemo(() => { + return arg?.items.edges?.nodes.map(identity); + }, [arg?.items.edges?.nodes]); + return ( + + ); +} +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: null}], + sequentialRenders: [ + {arg: null}, + {arg: null}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: null}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + {arg: {items: {edges: {nodes: [1, 2, 'hello']}}}}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md new file mode 100644 index 0000000000000..b4a55fcb61eee --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md @@ -0,0 +1,62 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + x.push(props.items); + return x; + }, [props.items]); + return ; +} + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import { ValidateMemoization } from "shared-runtime"; +function Component(props) { + const $ = _c(7); + let t0; + let x; + if ($[0] !== props.items) { + x = []; + x.push(props?.items); + x.push(props.items); + $[0] = props.items; + $[1] = x; + } else { + x = $[1]; + } + t0 = x; + const data = t0; + let t1; + if ($[2] !== props.items) { + t1 = [props.items]; + $[2] = props.items; + $[3] = t1; + } else { + t1 = $[3]; + } + let t2; + if ($[4] !== t1 || $[5] !== data) { + t2 = ; + $[4] = t1; + $[5] = data; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} + +``` + +### Eval output +(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single-with-unconditional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/error.todo-optional-member-expression-single-with-unconditional.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md new file mode 100644 index 0000000000000..f15b9b8e9b816 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md @@ -0,0 +1,91 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import {ValidateMemoization} from 'shared-runtime'; +import {useMemo} from 'react'; +function Component({arg}) { + const data = useMemo(() => { + const x = []; + x.push(arg?.items); + return x; + }, [arg?.items]); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: {items: 2}}], + sequentialRenders: [ + {arg: {items: 2}}, + {arg: {items: 2}}, + {arg: null}, + {arg: null}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import { ValidateMemoization } from "shared-runtime"; +import { useMemo } from "react"; +function Component(t0) { + const $ = _c(7); + const { arg } = t0; + + arg?.items; + let t1; + let x; + if ($[0] !== arg?.items) { + x = []; + x.push(arg?.items); + $[0] = arg?.items; + $[1] = x; + } else { + x = $[1]; + } + t1 = x; + const data = t1; + const t2 = arg?.items; + let t3; + if ($[2] !== t2) { + t3 = [t2]; + $[2] = t2; + $[3] = t3; + } else { + t3 = $[3]; + } + let t4; + if ($[4] !== t3 || $[5] !== data) { + t4 = ; + $[4] = t3; + $[5] = data; + $[6] = t4; + } else { + t4 = $[6]; + } + return t4; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arg: { items: 2 } }], + sequentialRenders: [ + { arg: { items: 2 } }, + { arg: { items: 2 } }, + { arg: null }, + { arg: null }, + ], +}; + +``` + +### Eval output +(kind: ok)
{"inputs":[2],"output":[2]}
+
{"inputs":[2],"output":[2]}
+
{"inputs":[null],"output":[null]}
+
{"inputs":[null],"output":[null]}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.js new file mode 100644 index 0000000000000..8f54a0edb517d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.js @@ -0,0 +1,22 @@ +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies @enablePropagateDepsInHIR +import {ValidateMemoization} from 'shared-runtime'; +import {useMemo} from 'react'; +function Component({arg}) { + const data = useMemo(() => { + const x = []; + x.push(arg?.items); + return x; + }, [arg?.items]); + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: {items: 2}}], + sequentialRenders: [ + {arg: {items: 2}}, + {arg: {items: 2}}, + {arg: null}, + {arg: null}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md index 6db3983d10751..9a524e6357a1b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md @@ -16,9 +16,9 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(2); let t0; - if ($[0] !== props.post.feedback.comments) { + if ($[0] !== props.post.feedback.comments?.edges) { t0 = props.post.feedback.comments?.edges?.map(render); - $[0] = props.post.feedback.comments; + $[0] = props.post.feedback.comments?.edges; $[1] = t0; } else { t0 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/conditional-member-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/conditional-member-expr.expect.md index d56dcb63aed18..f13bfe7d61705 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/conditional-member-expr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/conditional-member-expr.expect.md @@ -31,10 +31,10 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(2); let x; - if ($[0] !== props.a) { + if ($[0] !== props.a?.b) { x = []; x.push(props.a?.b); - $[0] = props.a; + $[0] = props.a?.b; $[1] = x; } else { x = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md index 0f155c79dea93..a13a918a312cb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain.expect.md @@ -46,11 +46,11 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(2); let x; - if ($[0] !== props.a) { + if ($[0] !== props.a.b) { x = []; x.push(props.a?.b); x.push(props.a.b.c); - $[0] = props.a; + $[0] = props.a.b; $[1] = x; } else { x = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md index cf2d1d413741e..df9dec4fb6827 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md @@ -22,16 +22,25 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { - const $ = _c(2); + const $ = _c(5); let x; - if ($[0] !== props.items) { + if ($[0] !== props.items?.length || $[1] !== props.items?.edges) { x = []; x.push(props.items?.length); - x.push(props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []); - $[0] = props.items; - $[1] = x; + let t0; + if ($[3] !== props.items?.edges) { + t0 = props.items?.edges?.map?.(render)?.filter?.(Boolean) ?? []; + $[3] = props.items?.edges; + $[4] = t0; + } else { + t0 = $[4]; + } + x.push(t0); + $[0] = props.items?.length; + $[1] = props.items?.edges; + $[2] = x; } else { - x = $[1]; + x = $[2]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.expect.md new file mode 100644 index 0000000000000..8703c30cb09e0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.expect.md @@ -0,0 +1,72 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR +import {identity} from 'shared-runtime'; + +/** + * Very contrived text fixture showing that it's technically incorrect to merge + * a conditional dependency (e.g. dep.path in `cond ? dep.path : ...`) and an + * unconditionally evaluated optional chain (`dep?.path`). + * + * + * when screen is non-null, useFoo returns { title: null } or "(not null)" + * when screen is null, useFoo throws + */ +function useFoo({screen}: {screen: null | undefined | {title_text: null}}) { + return screen?.title_text != null + ? '(not null)' + : identity({title: screen.title_text}); +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{screen: null}], + sequentialRenders: [{screen: {title_bar: undefined}}, {screen: null}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +import { identity } from "shared-runtime"; + +/** + * Very contrived text fixture showing that it's technically incorrect to merge + * a conditional dependency (e.g. dep.path in `cond ? dep.path : ...`) and an + * unconditionally evaluated optional chain (`dep?.path`). + * + * + * when screen is non-null, useFoo returns { title: null } or "(not null)" + * when screen is null, useFoo throws + */ +function useFoo(t0) { + const $ = _c(2); + const { screen } = t0; + let t1; + if ($[0] !== screen) { + t1 = + screen?.title_text != null + ? "(not null)" + : identity({ title: screen.title_text }); + $[0] = screen; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ screen: null }], + sequentialRenders: [{ screen: { title_bar: undefined } }, { screen: null }], +}; + +``` + +### Eval output +(kind: ok) {} +[[ (exception in render) TypeError: Cannot read properties of null (reading 'title_text') ]] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.ts new file mode 100644 index 0000000000000..2275412d777be --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/merge-uncond-optional-chain-and-cond.ts @@ -0,0 +1,22 @@ +// @enablePropagateDepsInHIR +import {identity} from 'shared-runtime'; + +/** + * Very contrived text fixture showing that it's technically incorrect to merge + * a conditional dependency (e.g. dep.path in `cond ? dep.path : ...`) and an + * unconditionally evaluated optional chain (`dep?.path`). + * + * + * when screen is non-null, useFoo returns { title: null } or "(not null)" + * when screen is null, useFoo throws + */ +function useFoo({screen}: {screen: null | undefined | {title_text: null}}) { + return screen?.title_text != null + ? '(not null)' + : identity({title: screen.title_text}); +} +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{screen: null}], + sequentialRenders: [{screen: {title_bar: undefined}}, {screen: null}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md index cf4e4f93274bb..39f301432e51f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-scope-missing-mutable-range.expect.md @@ -24,14 +24,14 @@ function HomeDiscoStoreItemTileRating(props) { const $ = _c(4); const item = useFragment(); let count; - if ($[0] !== item) { + if ($[0] !== item?.aggregates) { count = 0; const aggregates = item?.aggregates || []; aggregates.forEach((aggregate) => { count = count + (aggregate.count || 0); count; }); - $[0] = item; + $[0] = item?.aggregates; $[1] = count; } else { count = $[1]; From edacbde73f50cc9dc00819d61275cd43f12665c1 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:55:59 -0400 Subject: [PATCH 232/426] [compiler][hir-rewrite] Check mutability of base identifier when hoisting (#31032) Stack from [ghstack](https://github.com/ezyang/ghstack) (oldest at bottom): * #31066 * __->__ #31032 Prior to this PR, we check whether the property load source (e.g. the evaluation of `` in `.property`) is mutable + scoped to determine whether the property load itself is eligible for hoisting. This changes to check the base identifier of the load. - This is needed for the next PR #31066. We want to evaluate whether the base identifier is mutable within the context of the *outermost function*. This is because all LoadLocals and PropertyLoads within a nested function declaration have mutable-ranges within the context of the function, but the base identifier is a context variable. - A side effect is that we no longer infer loads from props / other function arguments as mutable in edge cases (e.g. props escaping out of try-blocks or being assigned to context variables) --- .../src/HIR/CollectHoistablePropertyLoads.ts | 109 ++++++++---------- ...-try-catch-maybe-null-dependency.expect.md | 65 +++++++++++ .../bug-try-catch-maybe-null-dependency.ts | 22 ++++ .../try-catch-maybe-null-dependency.expect.md | 79 +++++++++++++ .../try-catch-maybe-null-dependency.ts | 23 ++++ ...value-modified-in-catch-escaping.expect.md | 11 +- ...atch-try-value-modified-in-catch.expect.md | 11 +- .../packages/snap/src/SproutTodoFilter.ts | 1 + 8 files changed, 250 insertions(+), 71 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index 3603416ee6887..3118db2378e6d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -15,7 +15,7 @@ import { HIRFunction, Identifier, IdentifierId, - InstructionId, + InstructionValue, ReactiveScopeDependency, ScopeId, } from './HIR'; @@ -209,33 +209,23 @@ class PropertyPathRegistry { } } -function addNonNullPropertyPath( - source: Identifier, - sourceNode: PropertyPathNode, - instrId: InstructionId, - knownImmutableIdentifiers: Set, - result: Set, -): void { - /** - * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges - * are not valid with respect to current instruction id numbering. - * We use attached reactive scope ranges as a proxy for mutable range, but this - * is an overestimate as (1) scope ranges merge and align to form valid program - * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to - * non-mutable identifiers. - * - * See comment at top of function for why we track known immutable identifiers. - */ - const isMutableAtInstr = - source.mutableRange.end > source.mutableRange.start + 1 && - source.scope != null && - inRange({id: instrId}, source.scope.range); - if ( - !isMutableAtInstr || - knownImmutableIdentifiers.has(sourceNode.fullPath.identifier.id) - ) { - result.add(sourceNode); +function getMaybeNonNullInInstruction( + instr: InstructionValue, + temporaries: ReadonlyMap, + registry: PropertyPathRegistry, +): PropertyPathNode | null { + let path = null; + if (instr.kind === 'PropertyLoad') { + path = temporaries.get(instr.object.identifier.id) ?? { + identifier: instr.object.identifier, + path: [], + }; + } else if (instr.kind === 'Destructure') { + path = temporaries.get(instr.value.identifier.id) ?? null; + } else if (instr.kind === 'ComputedLoad') { + path = temporaries.get(instr.object.identifier.id) ?? null; } + return path != null ? registry.getOrCreateProperty(path) : null; } function collectNonNullsInBlocks( @@ -286,41 +276,38 @@ function collectNonNullsInBlocks( ); } for (const instr of block.instructions) { - if (instr.value.kind === 'PropertyLoad') { - const source = temporaries.get(instr.value.object.identifier.id) ?? { - identifier: instr.value.object.identifier, - path: [], - }; - addNonNullPropertyPath( - instr.value.object.identifier, - registry.getOrCreateProperty(source), - instr.id, - knownImmutableIdentifiers, - assumedNonNullObjects, - ); - } else if (instr.value.kind === 'Destructure') { - const source = instr.value.value.identifier.id; - const sourceNode = temporaries.get(source); - if (sourceNode != null) { - addNonNullPropertyPath( - instr.value.value.identifier, - registry.getOrCreateProperty(sourceNode), - instr.id, - knownImmutableIdentifiers, - assumedNonNullObjects, - ); - } - } else if (instr.value.kind === 'ComputedLoad') { - const source = instr.value.object.identifier.id; - const sourceNode = temporaries.get(source); - if (sourceNode != null) { - addNonNullPropertyPath( - instr.value.object.identifier, - registry.getOrCreateProperty(sourceNode), - instr.id, - knownImmutableIdentifiers, - assumedNonNullObjects, + const maybeNonNull = getMaybeNonNullInInstruction( + instr.value, + temporaries, + registry, + ); + if (maybeNonNull != null) { + const baseIdentifier = maybeNonNull.fullPath.identifier; + /** + * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges + * are not valid with respect to current instruction id numbering. + * We use attached reactive scope ranges as a proxy for mutable range, but this + * is an overestimate as (1) scope ranges merge and align to form valid program + * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to + * non-mutable identifiers. + * + * See comment at top of function for why we track known immutable identifiers. + */ + const isMutableAtInstr = + baseIdentifier.mutableRange.end > + baseIdentifier.mutableRange.start + 1 && + baseIdentifier.scope != null && + inRange( + { + id: instr.id, + }, + baseIdentifier.scope.range, ); + if ( + !isMutableAtInstr || + knownImmutableIdentifiers.has(baseIdentifier.id) + ) { + assumedNonNullObjects.add(maybeNonNull); } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md new file mode 100644 index 0000000000000..56ca1f7722e45 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md @@ -0,0 +1,65 @@ + +## Input + +```javascript +import {identity} from 'shared-runtime'; + +/** + * Not safe to hoist read of maybeNullObject.value.inner outside of the + * try-catch block, as that might throw + */ +function useFoo(maybeNullObject: {value: {inner: number}} | null) { + const y = []; + try { + y.push(identity(maybeNullObject.value.inner)); + } catch { + y.push('null'); + } + + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [null], + sequentialRenders: [null, {value: 2}, {value: 3}, null], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { identity } from "shared-runtime"; + +/** + * Not safe to hoist read of maybeNullObject.value.inner outside of the + * try-catch block, as that might throw + */ +function useFoo(maybeNullObject) { + const $ = _c(2); + let y; + if ($[0] !== maybeNullObject.value.inner) { + y = []; + try { + y.push(identity(maybeNullObject.value.inner)); + } catch { + y.push("null"); + } + $[0] = maybeNullObject.value.inner; + $[1] = y; + } else { + y = $[1]; + } + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [null], + sequentialRenders: [null, { value: 2 }, { value: 3 }, null], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.ts new file mode 100644 index 0000000000000..555ace19405a6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.ts @@ -0,0 +1,22 @@ +import {identity} from 'shared-runtime'; + +/** + * Not safe to hoist read of maybeNullObject.value.inner outside of the + * try-catch block, as that might throw + */ +function useFoo(maybeNullObject: {value: {inner: number}} | null) { + const y = []; + try { + y.push(identity(maybeNullObject.value.inner)); + } catch { + y.push('null'); + } + + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [null], + sequentialRenders: [null, {value: 2}, {value: 3}, null], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.expect.md new file mode 100644 index 0000000000000..cd2c4eb9dfd14 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.expect.md @@ -0,0 +1,79 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR +import {identity} from 'shared-runtime'; + +/** + * Not safe to hoist read of maybeNullObject.value.inner outside of the + * try-catch block, as that might throw + */ +function useFoo(maybeNullObject: {value: {inner: number}} | null) { + const y = []; + try { + y.push(identity(maybeNullObject.value.inner)); + } catch { + y.push('null'); + } + + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [null], + sequentialRenders: [null, {value: 2}, {value: 3}, null], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +import { identity } from "shared-runtime"; + +/** + * Not safe to hoist read of maybeNullObject.value.inner outside of the + * try-catch block, as that might throw + */ +function useFoo(maybeNullObject) { + const $ = _c(4); + let y; + if ($[0] !== maybeNullObject) { + y = []; + try { + let t0; + if ($[2] !== maybeNullObject.value.inner) { + t0 = identity(maybeNullObject.value.inner); + $[2] = maybeNullObject.value.inner; + $[3] = t0; + } else { + t0 = $[3]; + } + y.push(t0); + } catch { + y.push("null"); + } + $[0] = maybeNullObject; + $[1] = y; + } else { + y = $[1]; + } + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [null], + sequentialRenders: [null, { value: 2 }, { value: 3 }, null], +}; + +``` + +### Eval output +(kind: ok) ["null"] +[null] +[null] +["null"] \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.ts new file mode 100644 index 0000000000000..bdbd903117216 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-maybe-null-dependency.ts @@ -0,0 +1,23 @@ +// @enablePropagateDepsInHIR +import {identity} from 'shared-runtime'; + +/** + * Not safe to hoist read of maybeNullObject.value.inner outside of the + * try-catch block, as that might throw + */ +function useFoo(maybeNullObject: {value: {inner: number}} | null) { + const y = []; + try { + y.push(identity(maybeNullObject.value.inner)); + } catch { + y.push('null'); + } + + return y; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [null], + sequentialRenders: [null, {value: 2}, {value: 3}, null], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md index 914001f3737bd..f69994b0a8531 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md @@ -32,9 +32,9 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR const { throwInput } = require("shared-runtime"); function Component(props) { - const $ = _c(2); + const $ = _c(3); let x; - if ($[0] !== props) { + if ($[0] !== props.y || $[1] !== props.e) { try { const y = []; y.push(props.y); @@ -44,10 +44,11 @@ function Component(props) { e.push(props.e); x = e; } - $[0] = props; - $[1] = x; + $[0] = props.y; + $[1] = props.e; + $[2] = x; } else { - x = $[1]; + x = $[2]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md index 30ecdf6d59e9d..bc47228371f87 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md @@ -31,9 +31,9 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR const { throwInput } = require("shared-runtime"); function Component(props) { - const $ = _c(2); + const $ = _c(3); let t0; - if ($[0] !== props) { + if ($[0] !== props.y || $[1] !== props.e) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { try { @@ -47,10 +47,11 @@ function Component(props) { break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.y; + $[1] = props.e; + $[2] = t0; } else { - t0 = $[1]; + t0 = $[2]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 0ae22a643b326..c40392884d579 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -478,6 +478,7 @@ const skipFilter = new Set([ 'fbt/bug-fbt-plural-multiple-function-calls', 'fbt/bug-fbt-plural-multiple-mixed-call-tag', 'bug-invalid-hoisting-functionexpr', + 'bug-try-catch-maybe-null-dependency', 'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond', 'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block', 'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope', From 1460d67c5b9a0d4498b4d22e1a5a6c0ccac85fdd Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:41:32 -0400 Subject: [PATCH 233/426] [compiler][hir] Only hoist always-accessed PropertyLoads from function decls (#31066) Stack from [ghstack](https://github.com/ezyang/ghstack) (oldest at bottom): * __->__ #31066 * #31032 Prior to this PR, we consider all of a nested function's accessed paths as 'hoistable' (to the basic block in which the function was defined). Now, we traverse nested functions and find all paths hoistable to their *entry block*. Note that this only replaces the *hoisting* part of function declarations, not dependencies. This realistically only affects optional chains within functions, which always get truncated to its inner non-optional path (see [todo-infer-function-uncond-optionals-hoisted.tsx](https://github.com/facebook/react/blob/576f3c0aa898cb99da1b7bf15317756e25c13708/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx)) See newly added test fixtures for details Update: Note that toggling `enableTreatFunctionDepsAsConditional` makes a non-trivial impact on granularity of inferred deps (i.e. we find that function declarations uniquely identify some paths as hoistable). Snapshot comparison of internal code shows ~2.5% of files get worse dependencies ([internal link](https://www.internalfb.com/phabricator/paste/view/P1625792186)) --- .../src/HIR/CollectHoistablePropertyLoads.ts | 231 ++++++++++++------ .../src/HIR/PropagateScopeDependenciesHIR.ts | 12 +- ...r-function-cond-access-local-var.expect.md | 97 ++++++++ .../infer-function-cond-access-local-var.tsx | 33 +++ ...function-cond-access-not-hoisted.expect.md | 80 ++++++ ...infer-function-cond-access-not-hoisted.tsx | 25 ++ ...r-function-uncond-access-hoisted.expect.md | 52 ++++ .../infer-function-uncond-access-hoisted.tsx | 13 + ...n-uncond-access-hoists-other-dep.expect.md | 92 +++++++ ...unction-uncond-access-hoists-other-dep.tsx | 25 ++ ...function-uncond-access-local-var.expect.md | 73 ++++++ ...infer-function-uncond-access-local-var.tsx | 16 ++ ...uncond-optional-hoists-other-dep.expect.md | 91 +++++++ ...ction-uncond-optional-hoists-other-dep.tsx | 24 ++ ...function-uncond-access-local-var.expect.md | 73 ++++++ ...ested-function-uncond-access-local-var.tsx | 16 ++ ...er-nested-function-uncond-access.expect.md | 66 +++++ .../infer-nested-function-uncond-access.tsx | 18 ++ ...nfer-object-method-uncond-access.expect.md | 70 ++++++ .../infer-object-method-uncond-access.tsx | 18 ++ ...unction-uncond-optionals-hoisted.expect.md | 64 +++++ ...nfer-function-uncond-optionals-hoisted.tsx | 18 ++ ...function-cond-access-not-hoisted.expect.md | 73 ++++++ ...infer-function-cond-access-not-hoisted.tsx | 23 ++ ...unction-uncond-optionals-hoisted.expect.md | 61 +++++ ...nfer-function-uncond-optionals-hoisted.tsx | 16 ++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 27 files changed, 1306 insertions(+), 75 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.tsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index 3118db2378e6d..80593d6275868 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -7,6 +7,7 @@ import { Set_union, getOrInsertDefault, } from '../Utils/utils'; +import {collectOptionalChainSidemap} from './CollectOptionalChainDependencies'; import { BasicBlock, BlockId, @@ -15,10 +16,12 @@ import { HIRFunction, Identifier, IdentifierId, + InstructionId, InstructionValue, ReactiveScopeDependency, ScopeId, } from './HIR'; +import {collectTemporariesSidemap} from './PropagateScopeDependenciesHIR'; /** * Helper function for `PropagateScopeDependencies`. Uses control flow graph @@ -83,28 +86,57 @@ export function collectHoistablePropertyLoads( fn: HIRFunction, temporaries: ReadonlyMap, hoistableFromOptionals: ReadonlyMap, -): ReadonlyMap { + nestedFnImmutableContext: ReadonlySet | null, +): ReadonlyMap { const registry = new PropertyPathRegistry(); - const nodes = collectNonNullsInBlocks( - fn, - temporaries, + const functionExpressionLoads = collectFunctionExpressionFakeLoads(fn); + const actuallyEvaluatedTemporaries = new Map( + [...temporaries].filter(([id]) => !functionExpressionLoads.has(id)), + ); + + /** + * Due to current limitations of mutable range inference, there are edge cases in + * which we infer known-immutable values (e.g. props or hook params) to have a + * mutable range and scope. + * (see `destructure-array-declaration-to-context-var` fixture) + * We track known immutable identifiers to reduce regressions (as PropagateScopeDeps + * is being rewritten to HIR). + */ + const knownImmutableIdentifiers = new Set(); + if (fn.fnType === 'Component' || fn.fnType === 'Hook') { + for (const p of fn.params) { + if (p.kind === 'Identifier') { + knownImmutableIdentifiers.add(p.identifier.id); + } + } + } + const nodes = collectNonNullsInBlocks(fn, { + temporaries: actuallyEvaluatedTemporaries, + knownImmutableIdentifiers, hoistableFromOptionals, registry, - ); + nestedFnImmutableContext, + }); propagateNonNull(fn, nodes, registry); - const nodesKeyedByScopeId = new Map(); + return nodes; +} + +export function keyByScopeId( + fn: HIRFunction, + source: ReadonlyMap, +): ReadonlyMap { + const keyedByScopeId = new Map(); for (const [_, block] of fn.body.blocks) { if (block.terminal.kind === 'scope') { - nodesKeyedByScopeId.set( + keyedByScopeId.set( block.terminal.scope.id, - nodes.get(block.terminal.block)!, + source.get(block.terminal.block)!, ); } } - - return nodesKeyedByScopeId; + return keyedByScopeId; } export type BlockInfo = { @@ -211,45 +243,75 @@ class PropertyPathRegistry { function getMaybeNonNullInInstruction( instr: InstructionValue, - temporaries: ReadonlyMap, - registry: PropertyPathRegistry, + context: CollectNonNullsInBlocksContext, ): PropertyPathNode | null { let path = null; if (instr.kind === 'PropertyLoad') { - path = temporaries.get(instr.object.identifier.id) ?? { + path = context.temporaries.get(instr.object.identifier.id) ?? { identifier: instr.object.identifier, path: [], }; } else if (instr.kind === 'Destructure') { - path = temporaries.get(instr.value.identifier.id) ?? null; + path = context.temporaries.get(instr.value.identifier.id) ?? null; } else if (instr.kind === 'ComputedLoad') { - path = temporaries.get(instr.object.identifier.id) ?? null; + path = context.temporaries.get(instr.object.identifier.id) ?? null; + } + return path != null ? context.registry.getOrCreateProperty(path) : null; +} + +function isImmutableAtInstr( + identifier: Identifier, + instr: InstructionId, + context: CollectNonNullsInBlocksContext, +): boolean { + if (context.nestedFnImmutableContext != null) { + /** + * Comparing instructions ids across inner-outer function bodies is not valid, as they are numbered + */ + return context.nestedFnImmutableContext.has(identifier.id); + } else { + /** + * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges + * are not valid with respect to current instruction id numbering. + * We use attached reactive scope ranges as a proxy for mutable range, but this + * is an overestimate as (1) scope ranges merge and align to form valid program + * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to + * non-mutable identifiers. + * + * See comment in exported function for why we track known immutable identifiers. + */ + const mutableAtInstr = + identifier.mutableRange.end > identifier.mutableRange.start + 1 && + identifier.scope != null && + inRange( + { + id: instr, + }, + identifier.scope.range, + ); + return ( + !mutableAtInstr || context.knownImmutableIdentifiers.has(identifier.id) + ); } - return path != null ? registry.getOrCreateProperty(path) : null; } +type CollectNonNullsInBlocksContext = { + temporaries: ReadonlyMap; + knownImmutableIdentifiers: ReadonlySet; + hoistableFromOptionals: ReadonlyMap; + registry: PropertyPathRegistry; + /** + * (For nested / inner function declarations) + * Context variables (i.e. captured from an outer scope) that are immutable. + * Note that this technically could be merged into `knownImmutableIdentifiers`, + * but are currently kept separate for readability. + */ + nestedFnImmutableContext: ReadonlySet | null; +}; function collectNonNullsInBlocks( fn: HIRFunction, - temporaries: ReadonlyMap, - hoistableFromOptionals: ReadonlyMap, - registry: PropertyPathRegistry, + context: CollectNonNullsInBlocksContext, ): ReadonlyMap { - /** - * Due to current limitations of mutable range inference, there are edge cases in - * which we infer known-immutable values (e.g. props or hook params) to have a - * mutable range and scope. - * (see `destructure-array-declaration-to-context-var` fixture) - * We track known immutable identifiers to reduce regressions (as PropagateScopeDeps - * is being rewritten to HIR). - */ - const knownImmutableIdentifiers = new Set(); - if (fn.fnType === 'Component' || fn.fnType === 'Hook') { - for (const p of fn.params) { - if (p.kind === 'Identifier') { - knownImmutableIdentifiers.add(p.identifier.id); - } - } - } /** * Known non-null objects such as functional component props can be safely * read from any block. @@ -261,7 +323,9 @@ function collectNonNullsInBlocks( fn.params[0].kind === 'Identifier' ) { const identifier = fn.params[0].identifier; - knownNonNullIdentifiers.add(registry.getOrCreateIdentifier(identifier)); + knownNonNullIdentifiers.add( + context.registry.getOrCreateIdentifier(identifier), + ); } const nodes = new Map(); for (const [_, block] of fn.body.blocks) { @@ -269,45 +333,48 @@ function collectNonNullsInBlocks( knownNonNullIdentifiers, ); - const maybeOptionalChain = hoistableFromOptionals.get(block.id); + const maybeOptionalChain = context.hoistableFromOptionals.get(block.id); if (maybeOptionalChain != null) { assumedNonNullObjects.add( - registry.getOrCreateProperty(maybeOptionalChain), + context.registry.getOrCreateProperty(maybeOptionalChain), ); } for (const instr of block.instructions) { - const maybeNonNull = getMaybeNonNullInInstruction( - instr.value, - temporaries, - registry, - ); - if (maybeNonNull != null) { - const baseIdentifier = maybeNonNull.fullPath.identifier; - /** - * Since this runs *after* buildReactiveScopeTerminals, identifier mutable ranges - * are not valid with respect to current instruction id numbering. - * We use attached reactive scope ranges as a proxy for mutable range, but this - * is an overestimate as (1) scope ranges merge and align to form valid program - * blocks and (2) passes like MemoizeFbtAndMacroOperands may assign scopes to - * non-mutable identifiers. - * - * See comment at top of function for why we track known immutable identifiers. - */ - const isMutableAtInstr = - baseIdentifier.mutableRange.end > - baseIdentifier.mutableRange.start + 1 && - baseIdentifier.scope != null && - inRange( - { - id: instr.id, - }, - baseIdentifier.scope.range, - ); - if ( - !isMutableAtInstr || - knownImmutableIdentifiers.has(baseIdentifier.id) - ) { - assumedNonNullObjects.add(maybeNonNull); + const maybeNonNull = getMaybeNonNullInInstruction(instr.value, context); + if ( + maybeNonNull != null && + isImmutableAtInstr(maybeNonNull.fullPath.identifier, instr.id, context) + ) { + assumedNonNullObjects.add(maybeNonNull); + } + if ( + instr.value.kind === 'FunctionExpression' && + !fn.env.config.enableTreatFunctionDepsAsConditional + ) { + const innerFn = instr.value.loweredFunc; + const innerTemporaries = collectTemporariesSidemap( + innerFn.func, + new Set(), + ); + const innerOptionals = collectOptionalChainSidemap(innerFn.func); + const innerHoistableMap = collectHoistablePropertyLoads( + innerFn.func, + innerTemporaries, + innerOptionals.hoistableObjects, + context.nestedFnImmutableContext ?? + new Set( + innerFn.func.context + .filter(place => + isImmutableAtInstr(place.identifier, instr.id, context), + ) + .map(place => place.identifier.id), + ), + ); + const innerHoistables = assertNonNull( + innerHoistableMap.get(innerFn.func.body.entry), + ); + for (const entry of innerHoistables.assumedNonNullObjects) { + assumedNonNullObjects.add(entry); } } } @@ -515,3 +582,27 @@ function reduceMaybeOptionalChains( } } while (changed); } + +function collectFunctionExpressionFakeLoads( + fn: HIRFunction, +): Set { + const sources = new Map(); + const functionExpressionReferences = new Set(); + + for (const [_, block] of fn.body.blocks) { + for (const {lvalue, value} of block.instructions) { + if (value.kind === 'FunctionExpression') { + for (const reference of value.loweredFunc.dependencies) { + let curr: IdentifierId | undefined = reference.identifier.id; + while (curr != null) { + functionExpressionReferences.add(curr); + curr = sources.get(curr); + } + } + } else if (value.kind === 'PropertyLoad') { + sources.set(lvalue.identifier.id, value.object.identifier.id); + } + } + } + return functionExpressionReferences; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index a7346e0e6b984..ab2cf4cf56157 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -17,7 +17,10 @@ import { areEqualPaths, IdentifierId, } from './HIR'; -import {collectHoistablePropertyLoads} from './CollectHoistablePropertyLoads'; +import { + collectHoistablePropertyLoads, + keyByScopeId, +} from './CollectHoistablePropertyLoads'; import { ScopeBlockTraversal, eachInstructionOperand, @@ -41,10 +44,9 @@ export function propagateScopeDependenciesHIR(fn: HIRFunction): void { hoistableObjects, } = collectOptionalChainSidemap(fn); - const hoistablePropertyLoads = collectHoistablePropertyLoads( + const hoistablePropertyLoads = keyByScopeId( fn, - temporaries, - hoistableObjects, + collectHoistablePropertyLoads(fn, temporaries, hoistableObjects, null), ); const scopeDeps = collectDependencies( @@ -209,7 +211,7 @@ function findTemporariesUsedOutsideDeclaringScope( * of $1, as the evaluation of `arr.length` changes between instructions $1 and * $3. We do not track $1 -> arr.length in this case. */ -function collectTemporariesSidemap( +export function collectTemporariesSidemap( fn: HIRFunction, usedOutsideDeclaringScope: ReadonlySet, ): ReadonlyMap { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md new file mode 100644 index 0000000000000..c0f8aa97cd47e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md @@ -0,0 +1,97 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {shallowCopy, mutate, Stringify} from 'shared-runtime'; + +function useFoo({ + a, + shouldReadA, +}: { + a: {b: {c: number}; x: number}; + shouldReadA: boolean; +}) { + const local = shallowCopy(a); + mutate(local); + return ( + { + if (shouldReadA) return local.b.c; + return null; + }} + shouldInvokeFns={true} + /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { shallowCopy, mutate, Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(5); + const { a, shouldReadA } = t0; + let local; + if ($[0] !== a) { + local = shallowCopy(a); + mutate(local); + $[0] = a; + $[1] = local; + } else { + local = $[1]; + } + let t1; + if ($[2] !== shouldReadA || $[3] !== local) { + t1 = ( + { + if (shouldReadA) { + return local.b.c; + } + return null; + }} + shouldInvokeFns={true} + /> + ); + $[2] = shouldReadA; + $[3] = local; + $[4] = t1; + } else { + t1 = $[4]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null, shouldReadA: true }], + sequentialRenders: [ + { a: null, shouldReadA: true }, + { a: null, shouldReadA: false }, + { a: { b: { c: 4 } }, shouldReadA: true }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] +
{"fn":{"kind":"Function","result":null},"shouldInvokeFns":true}
+
{"fn":{"kind":"Function","result":4},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.tsx new file mode 100644 index 0000000000000..fdf22dc970b15 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.tsx @@ -0,0 +1,33 @@ +// @enablePropagateDepsInHIR + +import {shallowCopy, mutate, Stringify} from 'shared-runtime'; + +function useFoo({ + a, + shouldReadA, +}: { + a: {b: {c: number}; x: number}; + shouldReadA: boolean; +}) { + const local = shallowCopy(a); + mutate(local); + return ( + { + if (shouldReadA) return local.b.c; + return null; + }} + shouldInvokeFns={true} + /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md new file mode 100644 index 0000000000000..e37b8365a2faf --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md @@ -0,0 +1,80 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function Foo({a, shouldReadA}) { + return ( + { + if (shouldReadA) return a.b.c; + return null; + }} + shouldInvokeFns={true} + /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { Stringify } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(3); + const { a, shouldReadA } = t0; + let t1; + if ($[0] !== shouldReadA || $[1] !== a) { + t1 = ( + { + if (shouldReadA) { + return a.b.c; + } + return null; + }} + shouldInvokeFns={true} + /> + ); + $[0] = shouldReadA; + $[1] = a; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ a: null, shouldReadA: true }], + sequentialRenders: [ + { a: null, shouldReadA: true }, + { a: null, shouldReadA: false }, + { a: { b: { c: 4 } }, shouldReadA: true }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function","result":null},"shouldInvokeFns":true}
+
{"fn":{"kind":"Function","result":4},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.tsx new file mode 100644 index 0000000000000..5c71d57750c38 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.tsx @@ -0,0 +1,25 @@ +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function Foo({a, shouldReadA}) { + return ( + { + if (shouldReadA) return a.b.c; + return null; + }} + shouldInvokeFns={true} + /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.expect.md new file mode 100644 index 0000000000000..1ddc7495bc3e4 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.expect.md @@ -0,0 +1,52 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + return a.b.c} shouldInvokeFns={true} />; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(2); + const { a } = t0; + let t1; + if ($[0] !== a.b.c) { + t1 = a.b.c} shouldInvokeFns={true} />; + $[0] = a.b.c; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [{ a: null }, { a: { b: { c: 4 } } }], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function","result":4},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.tsx new file mode 100644 index 0000000000000..9cc72a36d7e7b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoisted.tsx @@ -0,0 +1,13 @@ +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + return a.b.c} shouldInvokeFns={true} />; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md new file mode 100644 index 0000000000000..89b4d281f86dc --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md @@ -0,0 +1,92 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {identity, makeArray, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({a, cond}) { + // Assume fn will be uncond evaluated, so we can safely evaluate {a., + // a.b. [a, a.b.c]; + useIdentity(null); + const x = makeArray(); + if (cond) { + x.push(identity(a.b.c)); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, cond: true}], + sequentialRenders: [ + {a: null, cond: true}, + {a: {b: {c: 4}}, cond: true}, + {a: {b: {c: 4}}, cond: true}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { identity, makeArray, Stringify, useIdentity } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(8); + const { a, cond } = t0; + let t1; + if ($[0] !== a) { + t1 = () => [a, a.b.c]; + $[0] = a; + $[1] = t1; + } else { + t1 = $[1]; + } + const fn = t1; + useIdentity(null); + let x; + if ($[2] !== cond || $[3] !== a.b.c) { + x = makeArray(); + if (cond) { + x.push(identity(a.b.c)); + } + $[2] = cond; + $[3] = a.b.c; + $[4] = x; + } else { + x = $[4]; + } + let t2; + if ($[5] !== fn || $[6] !== x) { + t2 = ; + $[5] = fn; + $[6] = x; + $[7] = t2; + } else { + t2 = $[7]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ a: null, cond: true }], + sequentialRenders: [ + { a: null, cond: true }, + { a: { b: { c: 4 } }, cond: true }, + { a: { b: { c: 4 } }, cond: true }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function","result":[{"b":{"c":4}},4]},"x":[4],"shouldInvokeFns":true}
+
{"fn":{"kind":"Function","result":[{"b":{"c":4}},4]},"x":[4],"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.tsx new file mode 100644 index 0000000000000..a9956ed8a5ffe --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.tsx @@ -0,0 +1,25 @@ +// @enablePropagateDepsInHIR + +import {identity, makeArray, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({a, cond}) { + // Assume fn will be uncond evaluated, so we can safely evaluate {a., + // a.b. [a, a.b.c]; + useIdentity(null); + const x = makeArray(); + if (cond) { + x.push(identity(a.b.c)); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, cond: true}], + sequentialRenders: [ + {a: null, cond: true}, + {a: {b: {c: 4}}, cond: true}, + {a: {b: {c: 4}}, cond: true}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md new file mode 100644 index 0000000000000..741a30d7de24d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.expect.md @@ -0,0 +1,73 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {mutate, shallowCopy, Stringify} from 'shared-runtime'; + +function useFoo({a}: {a: {b: {c: number}}}) { + const local = shallowCopy(a); + mutate(local); + const fn = () => local.b.c; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { mutate, shallowCopy, Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(6); + const { a } = t0; + let local; + if ($[0] !== a) { + local = shallowCopy(a); + mutate(local); + $[0] = a; + $[1] = local; + } else { + local = $[1]; + } + let t1; + if ($[2] !== local.b.c) { + t1 = () => local.b.c; + $[2] = local.b.c; + $[3] = t1; + } else { + t1 = $[3]; + } + const fn = t1; + let t2; + if ($[4] !== fn) { + t2 = ; + $[4] = fn; + $[5] = t2; + } else { + t2 = $[5]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [{ a: null }, { a: { b: { c: 4 } } }], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] +
{"fn":{"kind":"Function","result":4},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.tsx new file mode 100644 index 0000000000000..16a0964351d0c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-local-var.tsx @@ -0,0 +1,16 @@ +// @enablePropagateDepsInHIR + +import {mutate, shallowCopy, Stringify} from 'shared-runtime'; + +function useFoo({a}: {a: {b: {c: number}}}) { + const local = shallowCopy(a); + mutate(local); + const fn = () => local.b.c; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md new file mode 100644 index 0000000000000..591e04de7ba15 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md @@ -0,0 +1,91 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {identity, makeArray, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({a, cond}) { + // Assume fn can be uncond evaluated, so we can safely evaluate a.b?.c. + const fn = () => [a, a.b?.c.d]; + useIdentity(null); + const arr = makeArray(); + if (cond) { + arr.push(identity(a.b?.c.e)); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, cond: true}], + sequentialRenders: [ + {a: null, cond: true}, + {a: {b: {c: {d: 5}}}, cond: true}, + {a: {b: null}, cond: false}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { identity, makeArray, Stringify, useIdentity } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(8); + const { a, cond } = t0; + let t1; + if ($[0] !== a) { + t1 = () => [a, a.b?.c.d]; + $[0] = a; + $[1] = t1; + } else { + t1 = $[1]; + } + const fn = t1; + useIdentity(null); + let arr; + if ($[2] !== cond || $[3] !== a.b?.c.e) { + arr = makeArray(); + if (cond) { + arr.push(identity(a.b?.c.e)); + } + $[2] = cond; + $[3] = a.b?.c.e; + $[4] = arr; + } else { + arr = $[4]; + } + let t2; + if ($[5] !== fn || $[6] !== arr) { + t2 = ; + $[5] = fn; + $[6] = arr; + $[7] = t2; + } else { + t2 = $[7]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ a: null, cond: true }], + sequentialRenders: [ + { a: null, cond: true }, + { a: { b: { c: { d: 5 } } }, cond: true }, + { a: { b: null }, cond: false }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function","result":[{"b":{"c":{"d":5}}},5]},"arr":[null],"shouldInvokeFns":true}
+
{"fn":{"kind":"Function","result":[{"b":null},null]},"arr":[],"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.tsx new file mode 100644 index 0000000000000..3b538de991dc0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.tsx @@ -0,0 +1,24 @@ +// @enablePropagateDepsInHIR + +import {identity, makeArray, Stringify, useIdentity} from 'shared-runtime'; + +function Foo({a, cond}) { + // Assume fn can be uncond evaluated, so we can safely evaluate a.b?.c. + const fn = () => [a, a.b?.c.d]; + useIdentity(null); + const arr = makeArray(); + if (cond) { + arr.push(identity(a.b?.c.e)); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, cond: true}], + sequentialRenders: [ + {a: null, cond: true}, + {a: {b: {c: {d: 5}}}, cond: true}, + {a: {b: null}, cond: false}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md new file mode 100644 index 0000000000000..ca65ce72bc172 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.expect.md @@ -0,0 +1,73 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {shallowCopy, Stringify, mutate} from 'shared-runtime'; + +function useFoo({a}: {a: {b: {c: number}}}) { + const local = shallowCopy(a); + mutate(local); + const fn = () => [() => local.b.c]; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { shallowCopy, Stringify, mutate } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(6); + const { a } = t0; + let local; + if ($[0] !== a) { + local = shallowCopy(a); + mutate(local); + $[0] = a; + $[1] = local; + } else { + local = $[1]; + } + let t1; + if ($[2] !== local.b.c) { + t1 = () => [() => local.b.c]; + $[2] = local.b.c; + $[3] = t1; + } else { + t1 = $[3]; + } + const fn = t1; + let t2; + if ($[4] !== fn) { + t2 = ; + $[4] = fn; + $[5] = t2; + } else { + t2 = $[5]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [{ a: null }, { a: { b: { c: 4 } } }], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of undefined (reading 'c') ]] +
{"fn":{"kind":"Function","result":[{"kind":"Function","result":4}]},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.tsx new file mode 100644 index 0000000000000..d351a19464bf5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access-local-var.tsx @@ -0,0 +1,16 @@ +// @enablePropagateDepsInHIR + +import {shallowCopy, Stringify, mutate} from 'shared-runtime'; + +function useFoo({a}: {a: {b: {c: number}}}) { + const local = shallowCopy(a); + mutate(local); + const fn = () => [() => local.b.c]; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md new file mode 100644 index 0000000000000..22b17977cbcbe --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.expect.md @@ -0,0 +1,66 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + const fn = () => { + return () => ({ + value: a.b.c, + }); + }; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(4); + const { a } = t0; + let t1; + if ($[0] !== a.b.c) { + t1 = () => () => ({ value: a.b.c }); + $[0] = a.b.c; + $[1] = t1; + } else { + t1 = $[1]; + } + const fn = t1; + let t2; + if ($[2] !== fn) { + t2 = ; + $[2] = fn; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [{ a: null }, { a: { b: { c: 4 } } }], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function","result":{"kind":"Function","result":{"value":4}}},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.tsx new file mode 100644 index 0000000000000..41d004a689d05 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-nested-function-uncond-access.tsx @@ -0,0 +1,18 @@ +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + const fn = () => { + return () => ({ + value: a.b.c, + }); + }; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md new file mode 100644 index 0000000000000..7d75470550dfa --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.expect.md @@ -0,0 +1,70 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {identity, Stringify} from 'shared-runtime'; + +function useFoo({a}) { + const x = { + fn() { + return identity(a.b.c); + }, + }; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { identity, Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(4); + const { a } = t0; + let t1; + if ($[0] !== a.b.c) { + t1 = { + fn() { + return identity(a.b.c); + }, + }; + $[0] = a.b.c; + $[1] = t1; + } else { + t1 = $[1]; + } + const x = t1; + let t2; + if ($[2] !== x) { + t2 = ; + $[2] = x; + $[3] = t2; + } else { + t2 = $[3]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [{ a: null }, { a: { b: { c: 4 } } }], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"x":{"fn":{"kind":"Function","result":4}},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.tsx new file mode 100644 index 0000000000000..b05b482bd31f2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-object-method-uncond-access.tsx @@ -0,0 +1,18 @@ +// @enablePropagateDepsInHIR + +import {identity, Stringify} from 'shared-runtime'; + +function useFoo({a}) { + const x = { + fn() { + return identity(a.b.c); + }, + }; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [{a: null}, {a: {b: {c: 4}}}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md new file mode 100644 index 0000000000000..02e60eff91d61 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md @@ -0,0 +1,64 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + return a.b?.c.d?.e} shouldInvokeFns={true} />; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: {b: null}}, + {a: {b: {c: {d: null}}}}, + {a: {b: {c: {d: {e: 4}}}}}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR + +import { Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(2); + const { a } = t0; + let t1; + if ($[0] !== a.b) { + t1 = a.b?.c.d?.e} shouldInvokeFns={true} />; + $[0] = a.b; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [ + { a: null }, + { a: { b: null } }, + { a: { b: { c: { d: null } } } }, + { a: { b: { c: { d: { e: 4 } } } } }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function"},"shouldInvokeFns":true}
+
{"fn":{"kind":"Function"},"shouldInvokeFns":true}
+
{"fn":{"kind":"Function","result":4},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx new file mode 100644 index 0000000000000..4a2072131e430 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx @@ -0,0 +1,18 @@ +// @enablePropagateDepsInHIR + +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + return a.b?.c.d?.e} shouldInvokeFns={true} />; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: {b: null}}, + {a: {b: {c: {d: null}}}}, + {a: {b: {c: {d: {e: 4}}}}}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md new file mode 100644 index 0000000000000..4d45d3f3c6da6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md @@ -0,0 +1,73 @@ + +## Input + +```javascript +import {Stringify} from 'shared-runtime'; + +function Foo({a, shouldReadA}) { + return ( + { + if (shouldReadA) return a.b.c; + return null; + }} + shouldInvokeFns={true} + /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { Stringify } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(3); + const { a, shouldReadA } = t0; + let t1; + if ($[0] !== shouldReadA || $[1] !== a.b.c) { + t1 = ( + { + if (shouldReadA) { + return a.b.c; + } + return null; + }} + shouldInvokeFns={true} + /> + ); + $[0] = shouldReadA; + $[1] = a.b.c; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ a: null, shouldReadA: true }], + sequentialRenders: [ + { a: null, shouldReadA: true }, + { a: null, shouldReadA: false }, + { a: { b: { c: 4 } }, shouldReadA: true }, + ], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.tsx new file mode 100644 index 0000000000000..e571ee7b953ec --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.tsx @@ -0,0 +1,23 @@ +import {Stringify} from 'shared-runtime'; + +function Foo({a, shouldReadA}) { + return ( + { + if (shouldReadA) return a.b.c; + return null; + }} + shouldInvokeFns={true} + /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md new file mode 100644 index 0000000000000..157e2de81a1ff --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.expect.md @@ -0,0 +1,61 @@ + +## Input + +```javascript +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + return a.b?.c.d?.e} shouldInvokeFns={true} />; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: {b: null}}, + {a: {b: {c: {d: null}}}}, + {a: {b: {c: {d: {e: 4}}}}}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(2); + const { a } = t0; + let t1; + if ($[0] !== a.b) { + t1 = a.b?.c.d?.e} shouldInvokeFns={true} />; + $[0] = a.b; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: null }], + sequentialRenders: [ + { a: null }, + { a: { b: null } }, + { a: { b: { c: { d: null } } } }, + { a: { b: { c: { d: { e: 4 } } } } }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"fn":{"kind":"Function"},"shouldInvokeFns":true}
+
{"fn":{"kind":"Function"},"shouldInvokeFns":true}
+
{"fn":{"kind":"Function","result":4},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx new file mode 100644 index 0000000000000..11d5858434cc8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/todo-infer-function-uncond-optionals-hoisted.tsx @@ -0,0 +1,16 @@ +import {Stringify} from 'shared-runtime'; + +function useFoo({a}) { + return a.b?.c.d?.e} shouldInvokeFns={true} />; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: null}], + sequentialRenders: [ + {a: null}, + {a: {b: null}}, + {a: {b: {c: {d: null}}}}, + {a: {b: {c: {d: {e: 4}}}}}, + ], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index c40392884d579..8597f66dbd788 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -479,6 +479,7 @@ const skipFilter = new Set([ 'fbt/bug-fbt-plural-multiple-mixed-call-tag', 'bug-invalid-hoisting-functionexpr', 'bug-try-catch-maybe-null-dependency', + 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted', 'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond', 'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block', 'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope', From 91c42a14c7a698fe6baeab770d3c2548fcdf32b4 Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 7 Oct 2024 12:39:14 -0400 Subject: [PATCH 234/426] [rcr][ez] Clean up unused $read from rcr (#31136) --- compiler/packages/react-compiler-runtime/src/index.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/packages/react-compiler-runtime/src/index.ts b/compiler/packages/react-compiler-runtime/src/index.ts index cefc934ae1d67..823a49ab8199f 100644 --- a/compiler/packages/react-compiler-runtime/src/index.ts +++ b/compiler/packages/react-compiler-runtime/src/index.ts @@ -36,14 +36,6 @@ export function c(size: number) { })[0]; } -export function $read(memoCache: MemoCache, index: number) { - const value = memoCache[index]; - if (value === $empty) { - throw new Error('useMemoCache: read before write'); - } - return value; -} - const LazyGuardDispatcher: {[key: string]: (...args: Array) => any} = {}; [ 'readContext', From 68d59d43d5640f7e44b46bfa7ee758de063767b4 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:09:39 -0400 Subject: [PATCH 235/426] [compiler][ez] Fix reanimated custom type defs for imports (#31137) When we added support for Reanimated, we didn't distinguish between true globals (i.e. identifiers with no static resolutions), module types, and imports #29188. For the past 3-4 months, Reanimated imports were not being matched to the correct hook / function shape we match globals and module imports against two different registries. This PR fixes our support for Reanimated library functions imported under `react-native-reanimated`. See test fixtures for details --- .../src/HIR/Environment.ts | 13 +++-- .../src/HIR/Globals.ts | 22 +++---- ...d-reanimated-shared-value-writes.expect.md | 36 ++++++++++++ ...mported-reanimated-shared-value-writes.jsx | 15 +++++ .../compiler/reanimated-no-memo-arg.expect.md | 2 + .../compiler/reanimated-no-memo-arg.js | 1 + .../reanimated-shared-value-writes.expect.md | 57 +++++++++++++++++++ .../reanimated-shared-value-writes.jsx | 18 ++++++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 9 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.jsx create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reanimated-shared-value-writes.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reanimated-shared-value-writes.jsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 50905bc581dc1..b7d2b645c5b53 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -16,7 +16,7 @@ import { DEFAULT_SHAPES, Global, GlobalRegistry, - installReAnimatedTypes, + getReanimatedModuleType, installTypeConfig, } from './Globals'; import { @@ -688,7 +688,8 @@ export class Environment { } if (config.enableCustomTypeDefinitionForReanimated) { - installReAnimatedTypes(this.#globals, this.#shapes); + const reanimatedModuleType = getReanimatedModuleType(this.#shapes); + this.#moduleTypes.set(REANIMATED_MODULE_NAME, reanimatedModuleType); } this.#contextIdentifiers = contextIdentifiers; @@ -734,11 +735,11 @@ export class Environment { } #resolveModuleType(moduleName: string, loc: SourceLocation): Global | null { - if (this.config.moduleTypeProvider == null) { - return null; - } let moduleType = this.#moduleTypes.get(moduleName); if (moduleType === undefined) { + if (this.config.moduleTypeProvider == null) { + return null; + } const unparsedModuleConfig = this.config.moduleTypeProvider(moduleName); if (unparsedModuleConfig != null) { const parsedModuleConfig = TypeSchema.safeParse(unparsedModuleConfig); @@ -957,6 +958,8 @@ export class Environment { } } +const REANIMATED_MODULE_NAME = 'react-native-reanimated'; + // From https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js#LL18C1-L23C2 export function isHookName(name: string): boolean { return /^use[A-Z0-9]/.test(name); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts index 1128c51caeb58..2525b87bd86bc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Globals.ts @@ -25,7 +25,7 @@ import { addHook, addObject, } from './ObjectShape'; -import {BuiltInType, PolyType} from './Types'; +import {BuiltInType, ObjectType, PolyType} from './Types'; import {TypeConfig} from './TypeSchema'; import {assertExhaustive} from '../Utils/utils'; import {isHookName} from './Environment'; @@ -652,10 +652,7 @@ export function installTypeConfig( } } -export function installReAnimatedTypes( - globals: GlobalRegistry, - registry: ShapeRegistry, -): void { +export function getReanimatedModuleType(registry: ShapeRegistry): ObjectType { // hooks that freeze args and return frozen value const frozenHooks = [ 'useFrameCallback', @@ -665,8 +662,9 @@ export function installReAnimatedTypes( 'useAnimatedReaction', 'useWorkletCallback', ]; + const reanimatedType: Array<[string, BuiltInType]> = []; for (const hook of frozenHooks) { - globals.set( + reanimatedType.push([ hook, addHook(registry, { positionalParams: [], @@ -677,7 +675,7 @@ export function installReAnimatedTypes( calleeEffect: Effect.Read, hookKind: 'Custom', }), - ); + ]); } /** @@ -686,7 +684,7 @@ export function installReAnimatedTypes( */ const mutableHooks = ['useSharedValue', 'useDerivedValue']; for (const hook of mutableHooks) { - globals.set( + reanimatedType.push([ hook, addHook(registry, { positionalParams: [], @@ -697,7 +695,7 @@ export function installReAnimatedTypes( calleeEffect: Effect.Read, hookKind: 'Custom', }), - ); + ]); } // functions that return mutable value @@ -711,7 +709,7 @@ export function installReAnimatedTypes( 'executeOnUIRuntimeSync', ]; for (const fn of funcs) { - globals.set( + reanimatedType.push([ fn, addFunction(registry, [], { positionalParams: [], @@ -721,6 +719,8 @@ export function installReAnimatedTypes( returnValueKind: ValueKind.Mutable, noAlias: true, }), - ); + ]); } + + return addObject(registry, null, reanimatedType); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md new file mode 100644 index 0000000000000..f1399a41b6fec --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.invalid-non-imported-reanimated-shared-value-writes.expect.md @@ -0,0 +1,36 @@ + +## Input + +```javascript +// @enableCustomTypeDefinitionForReanimated + +/** + * Test that a global (i.e. non-imported) useSharedValue is treated as an + * unknown hook. + */ +function SomeComponent() { + const sharedVal = useSharedValue(0); + return ( + + }}> + Click me + ); } @@ -28,7 +32,9 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react-forget-runtime"; // @runtimeModule="react-forget-runtime" +import { c as _c } from "react/compiler-runtime"; // @runtimeModule="react-compiler-runtime" +import { useState } from "react"; + function Component(props) { const $ = _c(5); const [x, setX] = useState(1); @@ -48,11 +54,13 @@ function Component(props) { let t1; if ($[3] !== t0) { t1 = ( - ); $[3] = t0; $[4] = t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js index 013a1be33081e..1e6d5f435dd32 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js @@ -1,4 +1,6 @@ -// @runtimeModule="react-forget-runtime" +// @runtimeModule="react-compiler-runtime" +import {useState} from 'react'; + function Component(props) { const [x, setX] = useState(1); let y; @@ -6,10 +8,12 @@ function Component(props) { y = x * 2; } return ( - + }}> + Click me + ); } From 23cd3aca283817b8c359e806e9c7bc6b26fcd27c Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 7 Oct 2024 18:07:12 -0400 Subject: [PATCH 242/426] [rcr] Remove runtimeModule compiler option (#31145) Now that the compiler always injects `react-compiler-runtime`, this option is unnecessary. --- .../src/Entrypoint/Options.ts | 12 --- .../userspace-use-memo-cache.expect.md | 80 ------------------- .../compiler/userspace-use-memo-cache.js | 24 ------ compiler/packages/snap/src/compiler.ts | 6 -- 4 files changed, 122 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts index b092800a2e12d..10bcebe44e976 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts @@ -87,17 +87,6 @@ export type PluginOptions = { */ compilationMode: CompilationMode; - /* - * If enabled, Forget will import `useMemoCache` from the given module - * instead of `react/compiler-runtime`. - * - * ``` - * // If set to "react-compiler-runtime" - * import {c as useMemoCache} from 'react-compiler-runtime'; - * ``` - */ - runtimeModule?: string | null | undefined; - /** * By default React Compiler will skip compilation of code that suppresses the default * React ESLint rules, since this is a strong indication that the code may be breaking React rules @@ -214,7 +203,6 @@ export const defaultOptions: PluginOptions = { logger: null, gating: null, noEmit: false, - runtimeModule: null, eslintSuppressionRules: null, flowSuppressions: true, ignoreUseNoForget: false, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.expect.md deleted file mode 100644 index 972d1069072bb..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.expect.md +++ /dev/null @@ -1,80 +0,0 @@ - -## Input - -```javascript -// @runtimeModule="react-compiler-runtime" -import {useState} from 'react'; - -function Component(props) { - const [x, setX] = useState(1); - let y; - if (props.cond) { - y = x * 2; - } - return ( - - ); -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [true], - isComponent: true, -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @runtimeModule="react-compiler-runtime" -import { useState } from "react"; - -function Component(props) { - const $ = _c(5); - const [x, setX] = useState(1); - let y; - if ($[0] !== props.cond || $[1] !== x) { - if (props.cond) { - y = x * 2; - } - $[0] = props.cond; - $[1] = x; - $[2] = y; - } else { - y = $[2]; - } - - const t0 = y; - let t1; - if ($[3] !== t0) { - t1 = ( - - ); - $[3] = t0; - $[4] = t1; - } else { - t1 = $[4]; - } - return t1; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [true], - isComponent: true, -}; - -``` - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js deleted file mode 100644 index 1e6d5f435dd32..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/userspace-use-memo-cache.js +++ /dev/null @@ -1,24 +0,0 @@ -// @runtimeModule="react-compiler-runtime" -import {useState} from 'react'; - -function Component(props) { - const [x, setX] = useState(1); - let y; - if (props.cond) { - y = x * 2; - } - return ( - - ); -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [true], - isComponent: true, -}; diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index 72212ea0e94d7..cd907575fb797 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -48,7 +48,6 @@ function makePluginOptions( let enableEmitFreeze = null; let enableEmitHookGuards = null; let compilationMode: CompilationMode = 'all'; - let runtimeModule = null; let panicThreshold: PanicThresholdOptions = 'all_errors'; let hookPattern: string | null = null; // TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false @@ -104,10 +103,6 @@ function makePluginOptions( importSpecifierName: '$dispatcherGuard', }; } - const runtimeModuleMatch = /@runtimeModule="([^"]+)"/.exec(firstLine); - if (runtimeModuleMatch) { - runtimeModule = runtimeModuleMatch[1]; - } const targetMatch = /@target="([^"]+)"/.exec(firstLine); if (targetMatch) { @@ -251,7 +246,6 @@ function makePluginOptions( gating, panicThreshold, noEmit: false, - runtimeModule, eslintSuppressionRules, flowSuppressions, ignoreUseNoForget, From f74f6cd945675158eb40402041305e7af4ce731c Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 7 Oct 2024 18:50:07 -0400 Subject: [PATCH 243/426] [rcr] Publish react-compiler-runtime to npm (#31146) Updates our publishing scripts to also publish react-compiler-runtime. --- compiler/packages/react-compiler-runtime/README.md | 5 +++++ compiler/scripts/release/shared/packages.js | 1 + 2 files changed, 6 insertions(+) create mode 100644 compiler/packages/react-compiler-runtime/README.md diff --git a/compiler/packages/react-compiler-runtime/README.md b/compiler/packages/react-compiler-runtime/README.md new file mode 100644 index 0000000000000..8f650f962dc50 --- /dev/null +++ b/compiler/packages/react-compiler-runtime/README.md @@ -0,0 +1,5 @@ +# react-compiler-runtime + +Backwards compatible shim for runtime APIs used by React Compiler. Primarily meant for React versions prior to 19, but it will also work on > 19. + +See also https://github.com/reactwg/react-compiler/discussions/6. diff --git a/compiler/scripts/release/shared/packages.js b/compiler/scripts/release/shared/packages.js index c5513d1470132..533041d119665 100644 --- a/compiler/scripts/release/shared/packages.js +++ b/compiler/scripts/release/shared/packages.js @@ -2,6 +2,7 @@ const PUBLISHABLE_PACKAGES = [ 'babel-plugin-react-compiler', 'eslint-plugin-react-compiler', 'react-compiler-healthcheck', + 'react-compiler-runtime', ]; module.exports = { From ed966dac4a025fd37580e8197e5b271044ffbd9f Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 7 Oct 2024 20:37:41 -0400 Subject: [PATCH 244/426] [compiler] Fix busted postinstall script (#31147) --- compiler/packages/babel-plugin-react-compiler/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/package.json b/compiler/packages/babel-plugin-react-compiler/package.json index d9bfe9de7320c..5891ce2b856ad 100644 --- a/compiler/packages/babel-plugin-react-compiler/package.json +++ b/compiler/packages/babel-plugin-react-compiler/package.json @@ -8,9 +8,8 @@ "dist" ], "scripts": { - "postinstall": "./scripts/link-react-compiler-runtime.sh", "build": "rimraf dist && rollup --config --bundleConfigAsCjs", - "test": "yarn snap:ci", + "test": "./scripts/link-react-compiler-runtime.sh && yarn snap:ci", "jest": "yarn build && ts-node node_modules/.bin/jest", "snap": "node ../snap/dist/main.js", "snap:build": "yarn workspace snap run build", From bf0c054649f0573c184499bd571f08150152c086 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 09:54:34 +0100 Subject: [PATCH 245/426] fix[react-devtools]: wrap key string in preformatted text html element (#31153) Fixes https://github.com/facebook/react/issues/28984. --- .../src/devtools/views/Components/Element.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Element.js b/packages/react-devtools-shared/src/devtools/views/Components/Element.js index 48bfbe90906ff..b58451cb51d23 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Element.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Element.js @@ -166,7 +166,7 @@ export default function Element({data, index, style}: Props): React.Node { className={styles.KeyValue} title={key} onDoubleClick={handleKeyDoubleClick}> - {key} +
{key}
" From dbf80c8d7a823041d83baff8b0dca8892ce27411 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 13:23:23 +0100 Subject: [PATCH 246/426] fix[react-devtools]: update profiling status before receiving response from backend (#31117) We can't wait for a response from Backend, because it might take some time to actually finish profiling. We should keep a flag on the frontend side, so user can quickly see the feedback in the UI. --- .../src/devtools/ProfilerStore.js | 52 ++++++++++++++----- .../src/devtools/store.js | 2 +- .../views/Profiler/ProfilerContext.js | 2 +- .../devtools/views/Settings/SettingsModal.js | 2 +- .../Settings/SettingsModalContextToggle.js | 2 +- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/ProfilerStore.js b/packages/react-devtools-shared/src/devtools/ProfilerStore.js index a55487ec19a37..5ed7e69f294b9 100644 --- a/packages/react-devtools-shared/src/devtools/ProfilerStore.js +++ b/packages/react-devtools-shared/src/devtools/ProfilerStore.js @@ -11,6 +11,7 @@ import EventEmitter from '../events'; import {prepareProfilingDataFrontendFromBackendAndStore} from './views/Profiler/utils'; import ProfilingCache from './ProfilingCache'; import Store from './store'; +import {logEvent} from 'react-devtools-shared/src/Logger'; import type {FrontendBridge} from 'react-devtools-shared/src/bridge'; import type {ProfilingDataBackend} from 'react-devtools-shared/src/backend/types'; @@ -67,7 +68,12 @@ export default class ProfilerStore extends EventEmitter<{ // The backend is currently profiling. // When profiling is in progress, operations are stored so that we can later reconstruct past commit trees. - _isProfiling: boolean = false; + _isBackendProfiling: boolean = false; + + // Mainly used for optimistic UI. + // This could be false, but at the same time _isBackendProfiling could be true + // for cases when Backend is busy serializing a chunky payload. + _isProfilingBasedOnUserInput: boolean = false; // Tracks whether a specific renderer logged any profiling data during the most recent session. _rendererIDsThatReportedProfilingData: Set = new Set(); @@ -86,7 +92,8 @@ export default class ProfilerStore extends EventEmitter<{ super(); this._bridge = bridge; - this._isProfiling = defaultIsProfiling; + this._isBackendProfiling = defaultIsProfiling; + this._isProfilingBasedOnUserInput = defaultIsProfiling; this._store = store; bridge.addListener('operations', this.onBridgeOperations); @@ -139,8 +146,8 @@ export default class ProfilerStore extends EventEmitter<{ return this._rendererQueue.size > 0 || this._dataBackends.length > 0; } - get isProfiling(): boolean { - return this._isProfiling; + get isProfilingBasedOnUserInput(): boolean { + return this._isProfilingBasedOnUserInput; } get profilingCache(): ProfilingCache { @@ -151,7 +158,7 @@ export default class ProfilerStore extends EventEmitter<{ return this._dataFrontend; } set profilingData(value: ProfilingDataFrontend | null): void { - if (this._isProfiling) { + if (this._isBackendProfiling) { console.warn( 'Profiling data cannot be updated while profiling is in progress.', ); @@ -186,6 +193,9 @@ export default class ProfilerStore extends EventEmitter<{ startProfiling(): void { this._bridge.send('startProfiling', this._store.recordChangeDescriptions); + this._isProfilingBasedOnUserInput = true; + this.emit('isProfiling'); + // Don't actually update the local profiling boolean yet! // Wait for onProfilingStatus() to confirm the status has changed. // This ensures the frontend and backend are in sync wrt which commits were profiled. @@ -195,8 +205,12 @@ export default class ProfilerStore extends EventEmitter<{ stopProfiling(): void { this._bridge.send('stopProfiling'); - // Don't actually update the local profiling boolean yet! - // Wait for onProfilingStatus() to confirm the status has changed. + // Backend might be busy serializing the payload, so we are going to display + // optimistic UI to the user that profiling is stopping. + this._isProfilingBasedOnUserInput = false; + this.emit('isProfiling'); + + // Wait for onProfilingStatus() to confirm the status has changed, this will update _isBackendProfiling. // This ensures the frontend and backend are in sync wrt which commits were profiled. // We do this to avoid mismatches on e.g. CommitTreeBuilder that would cause errors. } @@ -229,7 +243,7 @@ export default class ProfilerStore extends EventEmitter<{ const rendererID = operations[0]; const rootID = operations[1]; - if (this._isProfiling) { + if (this._isBackendProfiling) { let profilingOperations = this._inProgressOperationsByRootID.get(rootID); if (profilingOperations == null) { profilingOperations = [operations]; @@ -252,8 +266,8 @@ export default class ProfilerStore extends EventEmitter<{ onBridgeProfilingData: (dataBackend: ProfilingDataBackend) => void = dataBackend => { - if (this._isProfiling) { - // This should never happen, but if it does- ignore previous profiling data. + if (this._isBackendProfiling) { + // This should never happen, but if it does, then ignore previous profiling data. return; } @@ -289,7 +303,7 @@ export default class ProfilerStore extends EventEmitter<{ }; onProfilingStatus: (isProfiling: boolean) => void = isProfiling => { - if (this._isProfiling === isProfiling) { + if (this._isBackendProfiling === isProfiling) { return; } @@ -319,15 +333,25 @@ export default class ProfilerStore extends EventEmitter<{ }); } - this._isProfiling = isProfiling; + this._isBackendProfiling = isProfiling; + // _isProfilingBasedOnUserInput should already be updated from startProfiling, stopProfiling, or constructor. + if (this._isProfilingBasedOnUserInput !== isProfiling) { + logEvent({ + event_name: 'error', + error_message: `Unexpected profiling status. Expected ${this._isProfilingBasedOnUserInput.toString()}, but received ${isProfiling.toString()}.`, + error_stack: new Error().stack, + error_component_stack: null, + }); + + // If happened, fallback to displaying the value from Backend + this._isProfilingBasedOnUserInput = isProfiling; + } // Invalidate suspense cache if profiling data is being (re-)recorded. // Note that we clear again, in case any views read from the cache while profiling. // (That would have resolved a now-stale value without any profiling data.) this._cache.invalidate(); - this.emit('isProfiling'); - // If we've just finished a profiling session, we need to fetch data stored in each renderer interface // and re-assemble it on the front-end into a format (ProfilingDataFrontend) that can power the Profiler UI. // During this time, DevTools UI should probably not be interactive. diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js index 8af997d9287ef..9f4343beabf43 100644 --- a/packages/react-devtools-shared/src/devtools/store.js +++ b/packages/react-devtools-shared/src/devtools/store.js @@ -324,7 +324,7 @@ export default class Store extends EventEmitter<{ return this._componentFilters; } set componentFilters(value: Array): void { - if (this._profilerStore.isProfiling) { + if (this._profilerStore.isProfilingBasedOnUserInput) { // Re-mounting a tree while profiling is in progress might break a lot of assumptions. // If necessary, we could support this- but it doesn't seem like a necessary use case. this._throwAndEmitError( diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js b/packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js index f4ebc26a07259..1ef7bb2b7e5c7 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js @@ -98,7 +98,7 @@ function ProfilerContextController({children}: Props): React.Node { getCurrentValue: () => ({ didRecordCommits: profilerStore.didRecordCommits, isProcessingData: profilerStore.isProcessingData, - isProfiling: profilerStore.isProfiling, + isProfiling: profilerStore.isProfilingBasedOnUserInput, profilingData: profilerStore.profilingData, supportsProfiling: store.rootSupportsBasicProfiling, }), diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js index f6652ada3a860..023b342a0cb9a 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js @@ -39,7 +39,7 @@ export default function SettingsModal(): React.Node { // Explicitly disallow it for now. const isProfilingSubscription = useMemo( () => ({ - getCurrentValue: () => profilerStore.isProfiling, + getCurrentValue: () => profilerStore.isProfilingBasedOnUserInput, subscribe: (callback: Function) => { profilerStore.addListener('isProfiling', callback); return () => profilerStore.removeListener('isProfiling', callback); diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContextToggle.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContextToggle.js index 306f0715111ba..94fa5c411181e 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContextToggle.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsModalContextToggle.js @@ -29,7 +29,7 @@ export default function SettingsModalContextToggle(): React.Node { // Explicitly disallow it for now. const isProfilingSubscription = useMemo( () => ({ - getCurrentValue: () => profilerStore.isProfiling, + getCurrentValue: () => profilerStore.isProfilingBasedOnUserInput, subscribe: (callback: Function) => { profilerStore.addListener('isProfiling', callback); return () => profilerStore.removeListener('isProfiling', callback); From 389a2deebc2dc41deb268f4b543709989d688d69 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 13:26:16 +0100 Subject: [PATCH 247/426] refactor[react-devtools/fiber/renderer]: optimize durations resolution (#31118) Stacked on https://github.com/facebook/react/pull/31117. No need for sending long float numbers and to have resolution less than a microsecond, we end up formatting it on a Frontend side: https://github.com/facebook/react/blob/6c7b41da3de12be2d95c60181b3fe896f824f13a/packages/react-devtools-shared/src/devtools/views/Profiler/utils.js#L359-L360 --- .../src/backend/fiber/renderer.js | 24 +++++++++++++++---- .../src/backend/utils/index.js | 9 +++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 9732bf105ca6c..8ce815c31f731 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -44,6 +44,7 @@ import { } from 'react-devtools-shared/src/utils'; import { formatConsoleArgumentsToSingleString, + formatDurationToMicrosecondsGranularity, gt, gte, parseSourceFromComponentStack, @@ -5074,8 +5075,14 @@ export function attach( const fiberSelfDurations: Array<[number, number]> = []; for (let i = 0; i < durations.length; i += 3) { const fiberID = durations[i]; - fiberActualDurations.push([fiberID, durations[i + 1]]); - fiberSelfDurations.push([fiberID, durations[i + 2]]); + fiberActualDurations.push([ + fiberID, + formatDurationToMicrosecondsGranularity(durations[i + 1]), + ]); + fiberSelfDurations.push([ + fiberID, + formatDurationToMicrosecondsGranularity(durations[i + 2]), + ]); } commitData.push({ @@ -5083,11 +5090,18 @@ export function attach( changeDescriptions !== null ? Array.from(changeDescriptions.entries()) : null, - duration: maxActualDuration, - effectDuration, + duration: + formatDurationToMicrosecondsGranularity(maxActualDuration), + effectDuration: + effectDuration !== null + ? formatDurationToMicrosecondsGranularity(effectDuration) + : null, fiberActualDurations, fiberSelfDurations, - passiveEffectDuration, + passiveEffectDuration: + passiveEffectDuration !== null + ? formatDurationToMicrosecondsGranularity(passiveEffectDuration) + : null, priorityLevel, timestamp: commitTime, updaters, diff --git a/packages/react-devtools-shared/src/backend/utils/index.js b/packages/react-devtools-shared/src/backend/utils/index.js index 1e7934af9835b..c07536e422608 100644 --- a/packages/react-devtools-shared/src/backend/utils/index.js +++ b/packages/react-devtools-shared/src/backend/utils/index.js @@ -331,3 +331,12 @@ export function parseSourceFromComponentStack( return parseSourceFromFirefoxStack(componentStack); } + +// 0.123456789 => 0.123 +// Expects high-resolution timestamp in milliseconds, like from performance.now() +// Mainly used for optimizing the size of serialized profiling payload +export function formatDurationToMicrosecondsGranularity( + duration: number, +): number { + return Math.round(duration * 1000) / 1000; +} From 4a86ec5a66d0dd375f8433d380f71ade3e67d5d0 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 13:32:04 +0100 Subject: [PATCH 248/426] fix[react-devtools]: removed redundant startProfiling call (#31131) Stacked on https://github.com/facebook/react/pull/31118. See last commit. We don't need to call `startProfiling()` here, because we delegate this to the Renderer itself: https://github.com/facebook/react/blob/830e823cd2c6ee675636d31320b10350e8ade9ae/packages/react-devtools-shared/src/backend/fiber/renderer.js#L5227-L5232 Since this is de-facto the constructor of Renderer, this will be called earlier. Validated via testing the reload-to-profile for Chrome browser extension. --- packages/react-devtools-shared/src/backend/agent.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index 88450fe29ebc9..2a0e9feb3784a 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -714,10 +714,6 @@ export default class Agent extends EventEmitter<{ ) { this._rendererInterfaces[rendererID] = rendererInterface; - if (this._isProfiling) { - rendererInterface.startProfiling(this._recordChangeDescriptions); - } - rendererInterface.setTraceUpdatesEnabled(this._traceUpdatesEnabled); // When the renderer is attached, we need to tell it whether From 1d8d12005fc9d856c4c936b269adb4f52bf82e47 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 13:34:01 +0100 Subject: [PATCH 249/426] fix[react-devtools]: remove all listeners when Agent is shutdown (#31151) Based on https://github.com/facebook/react/pull/31049, credits to @EdmondChuiHW. What is happening here: 1. Once Agent is destroyed, unsubscribe own listeners and bridge listeners. 2. [Browser extension only] Once Agent is destroyed, unsubscribe listeners from BackendManager. 3. [Browser extension only] I've discovered that `backendManager.js` content script can get injected multiple times by the browser. When Frontend is initializing, it will create Store first, and then execute a content script for bootstraping backend manager. If Frontend was destroyed somewhere between these 2 steps, Backend won't be notified, because it is not initialized yet, so it will not unsubscribe listeners correctly. We might end up duplicating listeners, and the next time Frontend is launched, it will report an issues "Cannot add / remove node ...", because same operations are emitted twice. To reproduce 3 you can do the following: 1. Click reload-to-profile 2. Right after when both app and Chrome DevTools panel are reloaded, close Chrome DevTools. 3. Open Chrome DevTools again, open Profiler panel and observe "Cannot add / remove node ..." error in the UI. --- .../src/contentScripts/backendManager.js | 33 ++++++++++++++----- .../src/backend/agent.js | 3 ++ .../src/backend/fiber/renderer.js | 2 +- .../src/backend/index.js | 7 ++-- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/react-devtools-extensions/src/contentScripts/backendManager.js b/packages/react-devtools-extensions/src/contentScripts/backendManager.js index 9d3ec414330ed..63519b506dd96 100644 --- a/packages/react-devtools-extensions/src/contentScripts/backendManager.js +++ b/packages/react-devtools-extensions/src/contentScripts/backendManager.js @@ -16,6 +16,7 @@ import {COMPACT_VERSION_NAME} from 'react-devtools-extensions/src/utils'; import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils'; let welcomeHasInitialized = false; +const requiredBackends = new Set(); function welcome(event: $FlowFixMe) { if ( @@ -49,8 +50,6 @@ function welcome(event: $FlowFixMe) { setup(window.__REACT_DEVTOOLS_GLOBAL_HOOK__); } -window.addEventListener('message', welcome); - function setup(hook: ?DevToolsHook) { // this should not happen, but Chrome can be weird sometimes if (hook == null) { @@ -71,20 +70,27 @@ function setup(hook: ?DevToolsHook) { updateRequiredBackends(); // register renderers that inject themselves later. - hook.sub('renderer', ({renderer}) => { + const unsubscribeRendererListener = hook.sub('renderer', ({renderer}) => { registerRenderer(renderer, hook); updateRequiredBackends(); }); // listen for backend installations. - hook.sub('devtools-backend-installed', version => { - activateBackend(version, hook); - updateRequiredBackends(); + const unsubscribeBackendInstallationListener = hook.sub( + 'devtools-backend-installed', + version => { + activateBackend(version, hook); + updateRequiredBackends(); + }, + ); + + const unsubscribeShutdownListener: () => void = hook.sub('shutdown', () => { + unsubscribeRendererListener(); + unsubscribeBackendInstallationListener(); + unsubscribeShutdownListener(); }); } -const requiredBackends = new Set(); - function registerRenderer(renderer: ReactRenderer, hook: DevToolsHook) { let version = renderer.reconcilerVersion || renderer.version; if (!hasAssignedBackend(version)) { @@ -139,6 +145,7 @@ function activateBackend(version: string, hook: DevToolsHook) { // If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down, // and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here. hook.emit('shutdown'); + delete window.__REACT_DEVTOOLS_BACKEND_MANAGER_INJECTED__; }); initBackend(hook, agent, window, getIsReloadAndProfileSupported()); @@ -178,3 +185,13 @@ function updateRequiredBackends() { '*', ); } + +/* + * Make sure this is executed only once in case Frontend is reloaded multiple times while Backend is initializing + * We can't use `reactDevToolsAgent` field on a global Hook object, because it only cleaned up after both Frontend and Backend initialized + */ +if (!window.__REACT_DEVTOOLS_BACKEND_MANAGER_INJECTED__) { + window.__REACT_DEVTOOLS_BACKEND_MANAGER_INJECTED__ = true; + + window.addEventListener('message', welcome); +} diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index 2a0e9feb3784a..f5fde694e735d 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -750,6 +750,9 @@ export default class Agent extends EventEmitter<{ shutdown: () => void = () => { // Clean up the overlay if visible, and associated events. this.emit('shutdown'); + + this._bridge.removeAllListeners(); + this.removeAllListeners(); }; startProfiling: (recordChangeDescriptions: boolean) => void = diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 8ce815c31f731..91fe467a95b72 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -3473,7 +3473,7 @@ export function attach( } function cleanup() { - // We don't patch any methods so there is no cleanup. + isProfiling = false; } function rootSupportsProfiling(root: any) { diff --git a/packages/react-devtools-shared/src/backend/index.js b/packages/react-devtools-shared/src/backend/index.js index 86714b7f61476..ace5dbc8c03ce 100644 --- a/packages/react-devtools-shared/src/backend/index.js +++ b/packages/react-devtools-shared/src/backend/index.js @@ -80,15 +80,12 @@ export function initBackend( }); hook.reactDevtoolsAgent = null; }; - agent.addListener('shutdown', onAgentShutdown); - subs.push(() => { - agent.removeListener('shutdown', onAgentShutdown); - }); + // Agent's event listeners are cleaned up by Agent in `shutdown` implementation. + agent.addListener('shutdown', onAgentShutdown); agent.addListener('updateHookSettings', settings => { hook.settings = settings; }); - agent.addListener('getHookSettings', () => { if (hook.settings != null) { agent.onHookSettings(hook.settings); From bfe91fbecf183f85fc1c4f909e12a6833a247319 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 13:57:02 +0100 Subject: [PATCH 250/426] refactor[react-devtools]: flatten reload and profile config (#31132) Stacked on https://github.com/facebook/react/pull/31131. See last commit. This is a clean-up and a pre-requisite for next changes: 1. `ReloadAndProfileConfig` is now split into boolean value and settings object. This is mainly because I will add one more setting soon, and also because settings might be persisted for a longer time than the flag which signals if the Backend was reloaded for profiling. Ideally, this settings should probably be moved to the global Hook object, same as we did for console patching. 2. Host is now responsible for reseting the cached values, Backend will execute provided `onReloadAndProfileFlagsReset` callback. --- packages/react-devtools-core/src/backend.js | 41 ++++++++--- .../src/contentScripts/backendManager.js | 15 +++- .../src/contentScripts/installHook.js | 13 +++- packages/react-devtools-inline/src/backend.js | 14 +++- .../src/attachRenderer.js | 8 ++- .../src/backend/agent.js | 33 +++------ .../src/backend/fiber/renderer.js | 11 ++- .../src/backend/types.js | 12 +--- packages/react-devtools-shared/src/hook.js | 15 ++-- packages/react-devtools-shared/src/utils.js | 68 +++++++++---------- 10 files changed, 131 insertions(+), 99 deletions(-) diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index 54a6b9b48a99d..9305155ab0e55 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -26,8 +26,7 @@ import type { import type { DevToolsHook, DevToolsHookSettings, - ReloadAndProfileConfig, - ReloadAndProfileConfigPersistence, + ProfilingSettings, } from 'react-devtools-shared/src/backend/types'; import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; @@ -42,7 +41,9 @@ type ConnectOptions = { websocket?: ?WebSocket, onSettingsUpdated?: (settings: $ReadOnly) => void, isReloadAndProfileSupported?: boolean, - reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence, + isProfiling?: boolean, + onReloadAndProfile?: (recordChangeDescriptions: boolean) => void, + onReloadAndProfileFlagsReset?: () => void, }; let savedComponentFilters: Array = @@ -63,9 +64,15 @@ export function initialize( maybeSettingsOrSettingsPromise?: | DevToolsHookSettings | Promise, - reloadAndProfileConfig?: ReloadAndProfileConfig, + shouldStartProfilingNow: boolean = false, + profilingSettings?: ProfilingSettings, ) { - installHook(window, maybeSettingsOrSettingsPromise, reloadAndProfileConfig); + installHook( + window, + maybeSettingsOrSettingsPromise, + shouldStartProfilingNow, + profilingSettings, + ); } export function connectToDevTools(options: ?ConnectOptions) { @@ -86,7 +93,9 @@ export function connectToDevTools(options: ?ConnectOptions) { isAppActive = () => true, onSettingsUpdated, isReloadAndProfileSupported = getIsReloadAndProfileSupported(), - reloadAndProfileConfigPersistence, + isProfiling, + onReloadAndProfile, + onReloadAndProfileFlagsReset, } = options || {}; const protocol = useHttps ? 'wss' : 'ws'; @@ -180,7 +189,11 @@ export function connectToDevTools(options: ?ConnectOptions) { // TODO (npm-packages) Warn if "isBackendStorageAPISupported" // $FlowFixMe[incompatible-call] found when upgrading Flow - const agent = new Agent(bridge, reloadAndProfileConfigPersistence); + const agent = new Agent(bridge, isProfiling, onReloadAndProfile); + if (typeof onReloadAndProfileFlagsReset === 'function') { + onReloadAndProfileFlagsReset(); + } + if (onSettingsUpdated != null) { agent.addListener('updateHookSettings', onSettingsUpdated); } @@ -320,7 +333,9 @@ type ConnectWithCustomMessagingOptions = { resolveRNStyle?: ResolveNativeStyle, onSettingsUpdated?: (settings: $ReadOnly) => void, isReloadAndProfileSupported?: boolean, - reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence, + isProfiling?: boolean, + onReloadAndProfile?: (recordChangeDescriptions: boolean) => void, + onReloadAndProfileFlagsReset?: () => void, }; export function connectWithCustomMessagingProtocol({ @@ -331,7 +346,9 @@ export function connectWithCustomMessagingProtocol({ resolveRNStyle, onSettingsUpdated, isReloadAndProfileSupported = getIsReloadAndProfileSupported(), - reloadAndProfileConfigPersistence, + isProfiling, + onReloadAndProfile, + onReloadAndProfileFlagsReset, }: ConnectWithCustomMessagingOptions): Function { const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook == null) { @@ -368,7 +385,11 @@ export function connectWithCustomMessagingProtocol({ bridge.send('overrideComponentFilters', savedComponentFilters); } - const agent = new Agent(bridge, reloadAndProfileConfigPersistence); + const agent = new Agent(bridge, isProfiling, onReloadAndProfile); + if (typeof onReloadAndProfileFlagsReset === 'function') { + onReloadAndProfileFlagsReset(); + } + if (onSettingsUpdated != null) { agent.addListener('updateHookSettings', onSettingsUpdated); } diff --git a/packages/react-devtools-extensions/src/contentScripts/backendManager.js b/packages/react-devtools-extensions/src/contentScripts/backendManager.js index 63519b506dd96..402a137857622 100644 --- a/packages/react-devtools-extensions/src/contentScripts/backendManager.js +++ b/packages/react-devtools-extensions/src/contentScripts/backendManager.js @@ -14,6 +14,11 @@ import type { import {hasAssignedBackend} from 'react-devtools-shared/src/backend/utils'; import {COMPACT_VERSION_NAME} from 'react-devtools-extensions/src/utils'; import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils'; +import { + getIfReloadedAndProfiling, + onReloadAndProfile, + onReloadAndProfileFlagsReset, +} from 'react-devtools-shared/src/utils'; let welcomeHasInitialized = false; const requiredBackends = new Set(); @@ -140,7 +145,15 @@ function activateBackend(version: string, hook: DevToolsHook) { }, }); - const agent = new Agent(bridge); + const agent = new Agent( + bridge, + getIfReloadedAndProfiling(), + onReloadAndProfile, + ); + // Agent read flags successfully, we can count it as successful launch + // Clean up flags, so that next reload won't start profiling + onReloadAndProfileFlagsReset(); + agent.addListener('shutdown', () => { // If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down, // and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here. diff --git a/packages/react-devtools-extensions/src/contentScripts/installHook.js b/packages/react-devtools-extensions/src/contentScripts/installHook.js index b7b96ed24714b..e70e97b285711 100644 --- a/packages/react-devtools-extensions/src/contentScripts/installHook.js +++ b/packages/react-devtools-extensions/src/contentScripts/installHook.js @@ -1,4 +1,8 @@ import {installHook} from 'react-devtools-shared/src/hook'; +import { + getIfReloadedAndProfiling, + getProfilingSettings, +} from 'react-devtools-shared/src/utils'; let resolveHookSettingsInjection; @@ -34,8 +38,15 @@ if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { payload: {handshake: true}, }); + const shouldStartProfiling = getIfReloadedAndProfiling(); + const profilingSettings = getProfilingSettings(); // Can't delay hook installation, inject settings lazily - installHook(window, hookSettingsPromise); + installHook( + window, + hookSettingsPromise, + shouldStartProfiling, + profilingSettings, + ); // Detect React window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on( diff --git a/packages/react-devtools-inline/src/backend.js b/packages/react-devtools-inline/src/backend.js index 41af7809be0b1..354970446db9b 100644 --- a/packages/react-devtools-inline/src/backend.js +++ b/packages/react-devtools-inline/src/backend.js @@ -8,7 +8,12 @@ import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyl import type {BackendBridge} from 'react-devtools-shared/src/bridge'; import type {Wall} from 'react-devtools-shared/src/frontend/types'; -import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils'; +import { + getIfReloadedAndProfiling, + getIsReloadAndProfileSupported, + onReloadAndProfile, + onReloadAndProfileFlagsReset, +} from 'react-devtools-shared/src/utils'; function startActivation(contentWindow: any, bridge: BackendBridge) { const onSavedPreferences = (data: $FlowFixMe) => { @@ -63,7 +68,12 @@ function startActivation(contentWindow: any, bridge: BackendBridge) { } function finishActivation(contentWindow: any, bridge: BackendBridge) { - const agent = new Agent(bridge); + const agent = new Agent( + bridge, + getIfReloadedAndProfiling(), + onReloadAndProfile, + ); + onReloadAndProfileFlagsReset(); const hook = contentWindow.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook) { diff --git a/packages/react-devtools-shared/src/attachRenderer.js b/packages/react-devtools-shared/src/attachRenderer.js index cd7a348b65d71..fedf76293cb47 100644 --- a/packages/react-devtools-shared/src/attachRenderer.js +++ b/packages/react-devtools-shared/src/attachRenderer.js @@ -12,8 +12,8 @@ import type { RendererInterface, DevToolsHook, RendererID, + ProfilingSettings, } from 'react-devtools-shared/src/backend/types'; -import type {ReloadAndProfileConfig} from './backend/types'; import {attach as attachFlight} from 'react-devtools-shared/src/backend/flight/renderer'; import {attach as attachFiber} from 'react-devtools-shared/src/backend/fiber/renderer'; @@ -30,7 +30,8 @@ export default function attachRenderer( id: RendererID, renderer: ReactRenderer, global: Object, - reloadAndProfileConfig: ReloadAndProfileConfig, + shouldStartProfilingNow: boolean, + profilingSettings: ProfilingSettings, ): RendererInterface | void { // only attach if the renderer is compatible with the current version of the backend if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) { @@ -55,7 +56,8 @@ export default function attachRenderer( id, renderer, global, - reloadAndProfileConfig, + shouldStartProfilingNow, + profilingSettings, ); } else if (renderer.ComponentTree) { // react-dom v15 diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index f5fde694e735d..12704899ecbdc 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -26,11 +26,9 @@ import type { RendererID, RendererInterface, DevToolsHookSettings, - ReloadAndProfileConfigPersistence, } from './types'; import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types'; import {isReactNativeEnvironment} from './utils'; -import {defaultReloadAndProfileConfigPersistence} from '../utils'; import { sessionStorageGetItem, sessionStorageRemoveItem, @@ -151,33 +149,21 @@ export default class Agent extends EventEmitter<{ }> { _bridge: BackendBridge; _isProfiling: boolean = false; - _recordChangeDescriptions: boolean = false; _rendererInterfaces: {[key: RendererID]: RendererInterface, ...} = {}; _persistedSelection: PersistedSelection | null = null; _persistedSelectionMatch: PathMatch | null = null; _traceUpdatesEnabled: boolean = false; - _reloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence; + _onReloadAndProfile: ((recordChangeDescriptions: boolean) => void) | void; constructor( bridge: BackendBridge, - reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence = defaultReloadAndProfileConfigPersistence, + isProfiling: boolean = false, + onReloadAndProfile?: (recordChangeDescriptions: boolean) => void, ) { super(); - this._reloadAndProfileConfigPersistence = reloadAndProfileConfigPersistence; - const {getReloadAndProfileConfig, setReloadAndProfileConfig} = - reloadAndProfileConfigPersistence; - const reloadAndProfileConfig = getReloadAndProfileConfig(); - if (reloadAndProfileConfig.shouldReloadAndProfile) { - this._recordChangeDescriptions = - reloadAndProfileConfig.recordChangeDescriptions; - this._isProfiling = true; - - setReloadAndProfileConfig({ - shouldReloadAndProfile: false, - recordChangeDescriptions: false, - }); - } + this._isProfiling = isProfiling; + this._onReloadAndProfile = onReloadAndProfile; const persistedSelectionString = sessionStorageGetItem( SESSION_STORAGE_LAST_SELECTION_KEY, @@ -674,10 +660,9 @@ export default class Agent extends EventEmitter<{ reloadAndProfile: (recordChangeDescriptions: boolean) => void = recordChangeDescriptions => { - this._reloadAndProfileConfigPersistence.setReloadAndProfileConfig({ - shouldReloadAndProfile: true, - recordChangeDescriptions, - }); + if (typeof this._onReloadAndProfile === 'function') { + this._onReloadAndProfile(recordChangeDescriptions); + } // This code path should only be hit if the shell has explicitly told the Store that it supports profiling. // In that case, the shell must also listen for this specific message to know when it needs to reload the app. @@ -757,7 +742,6 @@ export default class Agent extends EventEmitter<{ startProfiling: (recordChangeDescriptions: boolean) => void = recordChangeDescriptions => { - this._recordChangeDescriptions = recordChangeDescriptions; this._isProfiling = true; for (const rendererID in this._rendererInterfaces) { const renderer = ((this._rendererInterfaces[ @@ -770,7 +754,6 @@ export default class Agent extends EventEmitter<{ stopProfiling: () => void = () => { this._isProfiling = false; - this._recordChangeDescriptions = false; for (const rendererID in this._rendererInterfaces) { const renderer = ((this._rendererInterfaces[ (rendererID: any) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 91fe467a95b72..57aca225b8d1f 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -104,7 +104,6 @@ import { supportsOwnerStacks, supportsConsoleTasks, } from './DevToolsFiberComponentStack'; -import type {ReloadAndProfileConfig} from '../types'; // $FlowFixMe[method-unbinding] const toString = Object.prototype.toString; @@ -136,6 +135,7 @@ import type { WorkTagMap, CurrentDispatcherRef, LegacyDispatcherRef, + ProfilingSettings, } from '../types'; import type { ComponentFilter, @@ -864,7 +864,8 @@ export function attach( rendererID: number, renderer: ReactRenderer, global: Object, - reloadAndProfileConfig: ReloadAndProfileConfig, + shouldStartProfilingNow: boolean, + profilingSettings: ProfilingSettings, ): RendererInterface { // Newer versions of the reconciler package also specific reconciler version. // If that version number is present, use it. @@ -5225,10 +5226,8 @@ export function attach( } // Automatically start profiling so that we don't miss timing info from initial "mount". - if (reloadAndProfileConfig.shouldReloadAndProfile) { - const shouldRecordChangeDescriptions = - reloadAndProfileConfig.recordChangeDescriptions; - startProfiling(shouldRecordChangeDescriptions); + if (shouldStartProfilingNow) { + startProfiling(profilingSettings.recordChangeDescriptions); } function getNearestFiber(devtoolsInstance: DevToolsInstance): null | Fiber { diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index c6f743546e49e..61546f2c289a6 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -485,20 +485,10 @@ export type DevToolsBackend = { setupNativeStyleEditor?: SetupNativeStyleEditor, }; -export type ReloadAndProfileConfig = { - shouldReloadAndProfile: boolean, +export type ProfilingSettings = { recordChangeDescriptions: boolean, }; -// Linter doesn't speak Flow's `Partial` type -// eslint-disable-next-line no-undef -type PartialReloadAndProfileConfig = Partial; - -export type ReloadAndProfileConfigPersistence = { - setReloadAndProfileConfig: (config: PartialReloadAndProfileConfig) => void, - getReloadAndProfileConfig: () => ReloadAndProfileConfig, -}; - export type DevToolsHook = { listeners: {[key: string]: Array, ...}, rendererInterfaces: Map, diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 3b45c7417d4e0..4aa6518cd1f4b 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -16,7 +16,7 @@ import type { RendererInterface, DevToolsBackend, DevToolsHookSettings, - ReloadAndProfileConfig, + ProfilingSettings, } from './backend/types'; import { @@ -27,7 +27,6 @@ import { import attachRenderer from './attachRenderer'; import formatConsoleArguments from 'react-devtools-shared/src/backend/utils/formatConsoleArguments'; import formatWithStyles from 'react-devtools-shared/src/backend/utils/formatWithStyles'; -import {defaultReloadAndProfileConfigPersistence} from './utils'; // React's custom built component stack strings match "\s{4}in" // Chrome's prefix matches "\s{4}at" @@ -51,12 +50,17 @@ function areStackTracesEqual(a: string, b: string): boolean { const targetConsole: Object = console; +const defaultProfilingSettings: ProfilingSettings = { + recordChangeDescriptions: false, +}; + export function installHook( target: any, maybeSettingsOrSettingsPromise?: | DevToolsHookSettings | Promise, - reloadAndProfileConfig?: ReloadAndProfileConfig = defaultReloadAndProfileConfigPersistence.getReloadAndProfileConfig(), + shouldStartProfilingNow: boolean = false, + profilingSettings: ProfilingSettings = defaultProfilingSettings, ): DevToolsHook | null { if (target.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { return null; @@ -195,6 +199,8 @@ export function installHook( } catch (err) {} } + // TODO: isProfiling should be stateful, and we should update it once profiling is finished + const isProfiling = shouldStartProfilingNow; let uidCounter = 0; function inject(renderer: ReactRenderer): number { const id = ++uidCounter; @@ -215,7 +221,8 @@ export function installHook( id, renderer, target, - reloadAndProfileConfig, + isProfiling, + profilingSettings, ); if (rendererInterface != null) { hook.rendererInterfaces.set(id, rendererInterface); diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index 715834334f360..d3f18920fce1f 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -56,8 +56,9 @@ import { localStorageGetItem, localStorageSetItem, sessionStorageGetItem, + sessionStorageRemoveItem, sessionStorageSetItem, -} from './storage'; +} from 'react-devtools-shared/src/storage'; import {meta} from './hydration'; import isArray from './isArray'; @@ -67,12 +68,11 @@ import type { SerializedElement as SerializedElementFrontend, LRUCache, } from 'react-devtools-shared/src/frontend/types'; -import type {SerializedElement as SerializedElementBackend} from 'react-devtools-shared/src/backend/types'; -import {isSynchronousXHRSupported} from './backend/utils'; import type { - ReloadAndProfileConfig, - ReloadAndProfileConfigPersistence, -} from './backend/types'; + ProfilingSettings, + SerializedElement as SerializedElementBackend, +} from 'react-devtools-shared/src/backend/types'; +import {isSynchronousXHRSupported} from './backend/utils'; // $FlowFixMe[method-unbinding] const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -990,34 +990,30 @@ export function getIsReloadAndProfileSupported(): boolean { return isBackendStorageAPISupported && isSynchronousXHRSupported(); } -export const defaultReloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence = - { - setReloadAndProfileConfig({ - shouldReloadAndProfile, - recordChangeDescriptions, - }): void { - if (shouldReloadAndProfile != null) { - sessionStorageSetItem( - SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, - shouldReloadAndProfile ? 'true' : 'false', - ); - } - if (recordChangeDescriptions != null) { - sessionStorageSetItem( - SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, - recordChangeDescriptions ? 'true' : 'false', - ); - } - }, - getReloadAndProfileConfig(): ReloadAndProfileConfig { - return { - shouldReloadAndProfile: - sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === - 'true', - recordChangeDescriptions: - sessionStorageGetItem( - SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, - ) === 'true', - }; - }, +// Expected to be used only by browser extension and react-devtools-inline +export function getIfReloadedAndProfiling(): boolean { + return ( + sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true' + ); +} + +export function getProfilingSettings(): ProfilingSettings { + return { + recordChangeDescriptions: + sessionStorageGetItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY) === + 'true', }; +} + +export function onReloadAndProfile(recordChangeDescriptions: boolean): void { + sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true'); + sessionStorageSetItem( + SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, + recordChangeDescriptions ? 'true' : 'false', + ); +} + +export function onReloadAndProfileFlagsReset(): void { + sessionStorageRemoveItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY); + sessionStorageRemoveItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY); +} From d5bba18b5d81f234657586865248c5b6849599cd Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 9 Oct 2024 15:27:04 +0100 Subject: [PATCH 251/426] fix[react-devtools]: record timeline data only when supported (#31154) Stacked on https://github.com/facebook/react/pull/31132. See last commit. There are 2 issues: 1. We've been recording timeline events, even if Timeline Profiler was not supported by the Host. We've been doing this for React Native, for example, which would significantly regress perf of recording a profiling session, but we were not even using this data. 2. Currently, we are generating component stack for every state update event. This is extremely expensive, and we should not be doing this. We can't currently fix the second one, because we would still need to generate all these stacks, and this would still take quite a lot of time. As of right now, we can't generate a component stack lazily without relying on the fact that reference to the Fiber is not stale. With `enableOwnerStacks` we could populate component stacks in some collection, which would be cached at the Backend, and then returned only once Frontend asks for it. This approach also eliminates the need for keeping a reference to a Fiber. --- .../src/backend/agent.js | 55 ++++++++------ .../src/backend/fiber/renderer.js | 18 ++++- .../src/backend/profilingHooks.js | 73 ++++++++++++------- .../src/backend/types.js | 6 +- packages/react-devtools-shared/src/bridge.js | 8 +- .../react-devtools-shared/src/constants.js | 2 + .../src/devtools/ProfilerStore.js | 5 +- .../views/Profiler/ReloadAndProfileButton.js | 7 +- packages/react-devtools-shared/src/hook.js | 1 + packages/react-devtools-shared/src/utils.js | 13 +++- 10 files changed, 126 insertions(+), 62 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index 12704899ecbdc..e05abf51aba46 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -153,12 +153,17 @@ export default class Agent extends EventEmitter<{ _persistedSelection: PersistedSelection | null = null; _persistedSelectionMatch: PathMatch | null = null; _traceUpdatesEnabled: boolean = false; - _onReloadAndProfile: ((recordChangeDescriptions: boolean) => void) | void; + _onReloadAndProfile: + | ((recordChangeDescriptions: boolean, recordTimeline: boolean) => void) + | void; constructor( bridge: BackendBridge, isProfiling: boolean = false, - onReloadAndProfile?: (recordChangeDescriptions: boolean) => void, + onReloadAndProfile?: ( + recordChangeDescriptions: boolean, + recordTimeline: boolean, + ) => void, ) { super(); @@ -658,17 +663,19 @@ export default class Agent extends EventEmitter<{ this._bridge.send('isReloadAndProfileSupportedByBackend', true); }; - reloadAndProfile: (recordChangeDescriptions: boolean) => void = - recordChangeDescriptions => { - if (typeof this._onReloadAndProfile === 'function') { - this._onReloadAndProfile(recordChangeDescriptions); - } + reloadAndProfile: ({ + recordChangeDescriptions: boolean, + recordTimeline: boolean, + }) => void = ({recordChangeDescriptions, recordTimeline}) => { + if (typeof this._onReloadAndProfile === 'function') { + this._onReloadAndProfile(recordChangeDescriptions, recordTimeline); + } - // This code path should only be hit if the shell has explicitly told the Store that it supports profiling. - // In that case, the shell must also listen for this specific message to know when it needs to reload the app. - // The agent can't do this in a way that is renderer agnostic. - this._bridge.send('reloadAppForProfiling'); - }; + // This code path should only be hit if the shell has explicitly told the Store that it supports profiling. + // In that case, the shell must also listen for this specific message to know when it needs to reload the app. + // The agent can't do this in a way that is renderer agnostic. + this._bridge.send('reloadAppForProfiling'); + }; renamePath: RenamePathParams => void = ({ hookID, @@ -740,17 +747,19 @@ export default class Agent extends EventEmitter<{ this.removeAllListeners(); }; - startProfiling: (recordChangeDescriptions: boolean) => void = - recordChangeDescriptions => { - this._isProfiling = true; - for (const rendererID in this._rendererInterfaces) { - const renderer = ((this._rendererInterfaces[ - (rendererID: any) - ]: any): RendererInterface); - renderer.startProfiling(recordChangeDescriptions); - } - this._bridge.send('profilingStatus', this._isProfiling); - }; + startProfiling: ({ + recordChangeDescriptions: boolean, + recordTimeline: boolean, + }) => void = ({recordChangeDescriptions, recordTimeline}) => { + this._isProfiling = true; + for (const rendererID in this._rendererInterfaces) { + const renderer = ((this._rendererInterfaces[ + (rendererID: any) + ]: any): RendererInterface); + renderer.startProfiling(recordChangeDescriptions, recordTimeline); + } + this._bridge.send('profilingStatus', this._isProfiling); + }; stopProfiling: () => void = () => { this._isProfiling = false; diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 57aca225b8d1f..d582e2a3ced96 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -5035,6 +5035,7 @@ export function attach( let isProfiling: boolean = false; let profilingStartTime: number = 0; let recordChangeDescriptions: boolean = false; + let recordTimeline: boolean = false; let rootToCommitProfilingMetadataMap: CommitProfilingMetadataMap | null = null; @@ -5176,12 +5177,16 @@ export function attach( } } - function startProfiling(shouldRecordChangeDescriptions: boolean) { + function startProfiling( + shouldRecordChangeDescriptions: boolean, + shouldRecordTimeline: boolean, + ) { if (isProfiling) { return; } recordChangeDescriptions = shouldRecordChangeDescriptions; + recordTimeline = shouldRecordTimeline; // Capture initial values as of the time profiling starts. // It's important we snapshot both the durations and the id-to-root map, @@ -5212,7 +5217,7 @@ export function attach( rootToCommitProfilingMetadataMap = new Map(); if (toggleProfilingStatus !== null) { - toggleProfilingStatus(true); + toggleProfilingStatus(true, recordTimeline); } } @@ -5221,13 +5226,18 @@ export function attach( recordChangeDescriptions = false; if (toggleProfilingStatus !== null) { - toggleProfilingStatus(false); + toggleProfilingStatus(false, recordTimeline); } + + recordTimeline = false; } // Automatically start profiling so that we don't miss timing info from initial "mount". if (shouldStartProfilingNow) { - startProfiling(profilingSettings.recordChangeDescriptions); + startProfiling( + profilingSettings.recordChangeDescriptions, + profilingSettings.recordTimeline, + ); } function getNearestFiber(devtoolsInstance: DevToolsInstance): null | Fiber { diff --git a/packages/react-devtools-shared/src/backend/profilingHooks.js b/packages/react-devtools-shared/src/backend/profilingHooks.js index 47a01035308e2..a8111713c9fb2 100644 --- a/packages/react-devtools-shared/src/backend/profilingHooks.js +++ b/packages/react-devtools-shared/src/backend/profilingHooks.js @@ -97,7 +97,10 @@ export function setPerformanceMock_ONLY_FOR_TESTING( } export type GetTimelineData = () => TimelineData | null; -export type ToggleProfilingStatus = (value: boolean) => void; +export type ToggleProfilingStatus = ( + value: boolean, + recordTimeline?: boolean, +) => void; type Response = { getTimelineData: GetTimelineData, @@ -839,7 +842,10 @@ export function createProfilingHooks({ } } - function toggleProfilingStatus(value: boolean) { + function toggleProfilingStatus( + value: boolean, + recordTimeline: boolean = false, + ) { if (isProfiling !== value) { isProfiling = value; @@ -875,34 +881,45 @@ export function createProfilingHooks({ currentReactComponentMeasure = null; currentReactMeasuresStack = []; currentFiberStacks = new Map(); - currentTimelineData = { - // Session wide metadata; only collected once. - internalModuleSourceToRanges, - laneToLabelMap: laneToLabelMap || new Map(), - reactVersion, - - // Data logged by React during profiling session. - componentMeasures: [], - schedulingEvents: [], - suspenseEvents: [], - thrownErrors: [], - - // Data inferred based on what React logs. - batchUIDToMeasuresMap: new Map(), - duration: 0, - laneToReactMeasureMap, - startTime: 0, - - // Data only available in Chrome profiles. - flamechart: [], - nativeEvents: [], - networkMeasures: [], - otherUserTimingMarks: [], - snapshots: [], - snapshotHeight: 0, - }; + if (recordTimeline) { + currentTimelineData = { + // Session wide metadata; only collected once. + internalModuleSourceToRanges, + laneToLabelMap: laneToLabelMap || new Map(), + reactVersion, + + // Data logged by React during profiling session. + componentMeasures: [], + schedulingEvents: [], + suspenseEvents: [], + thrownErrors: [], + + // Data inferred based on what React logs. + batchUIDToMeasuresMap: new Map(), + duration: 0, + laneToReactMeasureMap, + startTime: 0, + + // Data only available in Chrome profiles. + flamechart: [], + nativeEvents: [], + networkMeasures: [], + otherUserTimingMarks: [], + snapshots: [], + snapshotHeight: 0, + }; + } nextRenderShouldStartNewBatch = true; } else { + // This is __EXPENSIVE__. + // We could end up with hundreds of state updated, and for each one of them + // would try to create a component stack with possibly hundreds of Fibers. + // Creating a cache of component stacks won't help, generating a single stack is already expensive enough. + // We should find a way to lazily generate component stacks on demand, when user inspects a specific event. + // If we succeed with moving React DevTools Timeline Profiler to Performance panel, then Timeline Profiler would probably be removed. + // If not, then once enableOwnerStacks is adopted, revisit this again and cache component stacks per Fiber, + // but only return them when needed, sending hundreds of component stacks is beyond the Bridge's bandwidth. + // Postprocess Profile data if (currentTimelineData !== null) { currentTimelineData.schedulingEvents.forEach(event => { diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index 61546f2c289a6..9d9d9a8eb5e65 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -419,7 +419,10 @@ export type RendererInterface = { renderer: ReactRenderer | null, setTraceUpdatesEnabled: (enabled: boolean) => void, setTrackedPath: (path: Array | null) => void, - startProfiling: (recordChangeDescriptions: boolean) => void, + startProfiling: ( + recordChangeDescriptions: boolean, + recordTimeline: boolean, + ) => void, stopProfiling: () => void, storeAsGlobal: ( id: number, @@ -487,6 +490,7 @@ export type DevToolsBackend = { export type ProfilingSettings = { recordChangeDescriptions: boolean, + recordTimeline: boolean, }; export type DevToolsHook = { diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index dde6e7c3ffff8..cb494e1b3c1ba 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -16,6 +16,7 @@ import type { ProfilingDataBackend, RendererID, DevToolsHookSettings, + ProfilingSettings, } from 'react-devtools-shared/src/backend/types'; import type {StyleAndLayout as StyleAndLayoutPayload} from 'react-devtools-shared/src/backend/NativeStyleEditor/types'; @@ -206,6 +207,9 @@ export type BackendEvents = { hookSettings: [$ReadOnly], }; +type StartProfilingParams = ProfilingSettings; +type ReloadAndProfilingParams = ProfilingSettings; + type FrontendEvents = { clearErrorsAndWarnings: [{rendererID: RendererID}], clearErrorsForElementID: [ElementAndRendererID], @@ -226,13 +230,13 @@ type FrontendEvents = { overrideSuspense: [OverrideSuspense], overrideValueAtPath: [OverrideValueAtPath], profilingData: [ProfilingDataBackend], - reloadAndProfile: [boolean], + reloadAndProfile: [ReloadAndProfilingParams], renamePath: [RenamePath], savedPreferences: [SavedPreferencesParams], setTraceUpdatesEnabled: [boolean], shutdown: [], startInspectingHost: [], - startProfiling: [boolean], + startProfiling: [StartProfilingParams], stopInspectingHost: [boolean], stopProfiling: [], storeAsGlobal: [StoreAsGlobalParams], diff --git a/packages/react-devtools-shared/src/constants.js b/packages/react-devtools-shared/src/constants.js index 6893610b46d8f..b08738165906c 100644 --- a/packages/react-devtools-shared/src/constants.js +++ b/packages/react-devtools-shared/src/constants.js @@ -41,6 +41,8 @@ export const LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY = 'React::DevTools::parseHookNames'; export const SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY = 'React::DevTools::recordChangeDescriptions'; +export const SESSION_STORAGE_RECORD_TIMELINE_KEY = + 'React::DevTools::recordTimeline'; export const SESSION_STORAGE_RELOAD_AND_PROFILE_KEY = 'React::DevTools::reloadAndProfile'; export const LOCAL_STORAGE_BROWSER_THEME = 'React::DevTools::theme'; diff --git a/packages/react-devtools-shared/src/devtools/ProfilerStore.js b/packages/react-devtools-shared/src/devtools/ProfilerStore.js index 5ed7e69f294b9..b9bbdb11df539 100644 --- a/packages/react-devtools-shared/src/devtools/ProfilerStore.js +++ b/packages/react-devtools-shared/src/devtools/ProfilerStore.js @@ -191,7 +191,10 @@ export default class ProfilerStore extends EventEmitter<{ } startProfiling(): void { - this._bridge.send('startProfiling', this._store.recordChangeDescriptions); + this._bridge.send('startProfiling', { + recordChangeDescriptions: this._store.recordChangeDescriptions, + recordTimeline: this._store.supportsTimeline, + }); this._isProfilingBasedOnUserInput = true; this.emit('isProfiling'); diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/ReloadAndProfileButton.js b/packages/react-devtools-shared/src/devtools/views/Profiler/ReloadAndProfileButton.js index 90dba6f7d8359..95ac82a97323d 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/ReloadAndProfileButton.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/ReloadAndProfileButton.js @@ -54,8 +54,11 @@ export default function ReloadAndProfileButton({ // For now, let's just skip doing it entirely to avoid paying snapshot costs for data we don't need. // startProfiling(); - bridge.send('reloadAndProfile', recordChangeDescriptions); - }, [bridge, recordChangeDescriptions]); + bridge.send('reloadAndProfile', { + recordChangeDescriptions, + recordTimeline: store.supportsTimeline, + }); + }, [bridge, recordChangeDescriptions, store]); if (!supportsReloadAndProfile) { return null; diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 4aa6518cd1f4b..d754140f96541 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -52,6 +52,7 @@ const targetConsole: Object = console; const defaultProfilingSettings: ProfilingSettings = { recordChangeDescriptions: false, + recordTimeline: false, }; export function installHook( diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index d3f18920fce1f..bbf1599898d8a 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -38,6 +38,7 @@ import { LOCAL_STORAGE_OPEN_IN_EDITOR_URL, SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, + SESSION_STORAGE_RECORD_TIMELINE_KEY, } from './constants'; import { ComponentFilterElementType, @@ -1002,18 +1003,28 @@ export function getProfilingSettings(): ProfilingSettings { recordChangeDescriptions: sessionStorageGetItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY) === 'true', + recordTimeline: + sessionStorageGetItem(SESSION_STORAGE_RECORD_TIMELINE_KEY) === 'true', }; } -export function onReloadAndProfile(recordChangeDescriptions: boolean): void { +export function onReloadAndProfile( + recordChangeDescriptions: boolean, + recordTimeline: boolean, +): void { sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true'); sessionStorageSetItem( SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, recordChangeDescriptions ? 'true' : 'false', ); + sessionStorageSetItem( + SESSION_STORAGE_RECORD_TIMELINE_KEY, + recordTimeline ? 'true' : 'false', + ); } export function onReloadAndProfileFlagsReset(): void { sessionStorageRemoveItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY); sessionStorageRemoveItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY); + sessionStorageRemoveItem(SESSION_STORAGE_RECORD_TIMELINE_KEY); } From de43d560a8622fa44ba4162424437125564e906e Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 9 Oct 2024 16:46:35 -0400 Subject: [PATCH 252/426] [cleanup] remove flag enableAddPropertiesFastPath (#31062) The experiment was tested internally and rolled out, replacing the flag with `true`. --- .../src/ReactNativeAttributePayloadFabric.js | 11 ++--------- packages/shared/ReactFeatureFlags.js | 2 -- .../forks/ReactFeatureFlags.native-fb-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.native-fb.js | 1 - packages/shared/forks/ReactFeatureFlags.native-oss.js | 1 - .../shared/forks/ReactFeatureFlags.test-renderer.js | 1 - .../ReactFeatureFlags.test-renderer.native-fb.js | 1 - .../forks/ReactFeatureFlags.test-renderer.www.js | 1 - .../shared/forks/ReactFeatureFlags.www-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.www.js | 1 - 10 files changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js b/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js index 88d30a81f0a79..f97c31e3980b6 100644 --- a/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js +++ b/packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js @@ -14,10 +14,7 @@ import { } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; import isArray from 'shared/isArray'; -import { - enableAddPropertiesFastPath, - enableShallowPropDiffing, -} from 'shared/ReactFeatureFlags'; +import {enableShallowPropDiffing} from 'shared/ReactFeatureFlags'; import type {AttributeConfiguration} from './ReactNativeTypes'; @@ -537,11 +534,7 @@ export function create( props: Object, validAttributes: AttributeConfiguration, ): null | Object { - if (enableAddPropertiesFastPath) { - return fastAddProperties(null, props, validAttributes); - } else { - return addProperties(null, props, validAttributes); - } + return fastAddProperties(null, props, validAttributes); } export function diff( diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index cd9bfedacabd5..058e2be089b0f 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -141,8 +141,6 @@ export const enableServerComponentLogs = true; */ export const enablePersistedModeClonedFlag = false; -export const enableAddPropertiesFastPath = false; - export const enableOwnerStacks = __EXPERIMENTAL__; export const enableShallowPropDiffing = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index a7643f6f90151..457ec37b2f9ba 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -18,7 +18,6 @@ // add a test configuration for React Native. export const alwaysThrottleRetries = __VARIANT__; -export const enableAddPropertiesFastPath = __VARIANT__; export const enableObjectFiber = __VARIANT__; export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__; export const enablePersistedModeClonedFlag = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 9dcc0f5d033ed..bac5977f5e1b4 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -20,7 +20,6 @@ const dynamicFlags: DynamicExportsType = (dynamicFlagsUntyped: any); // the exports object every time a flag is read. export const { alwaysThrottleRetries, - enableAddPropertiesFastPath, enableFabricCompleteRootInCommitPhase, enableHiddenSubtreeInsertionEffectCleanup, enableObjectFiber, diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 741b44daf7926..d5f0d3bb9ca88 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -32,7 +32,6 @@ export const disableLegacyMode = false; export const disableSchedulerTimeoutInWorkLoop = false; export const disableStringRefs = true; export const disableTextareaChildren = false; -export const enableAddPropertiesFastPath = false; export const enableAsyncActions = true; export const enableAsyncDebugInfo = false; export const enableAsyncIterableChildren = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 5e7d56a2a6f3e..746778b7b2c27 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -78,7 +78,6 @@ export const disableClientCache = true; export const enableServerComponentLogs = true; export const enableInfiniteRenderLoopDetection = false; -export const enableAddPropertiesFastPath = false; export const renameElementSymbol = true; export const enableShallowPropDiffing = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 0cb1497eddb5f..ae2f868e1d49c 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -24,7 +24,6 @@ export const disableLegacyMode = false; export const disableSchedulerTimeoutInWorkLoop = false; export const disableStringRefs = true; export const disableTextareaChildren = false; -export const enableAddPropertiesFastPath = false; export const enableAsyncActions = true; export const enableAsyncDebugInfo = false; export const enableAsyncIterableChildren = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 59850bac75099..1fa1b40280ff3 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -89,7 +89,6 @@ export const enableReactTestRendererWarning = false; export const disableLegacyMode = true; export const disableDefaultPropsExceptForClasses = false; -export const enableAddPropertiesFastPath = false; export const renameElementSymbol = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index dbd00f671d84e..8a82b7f55241b 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -18,7 +18,6 @@ export const disableDefaultPropsExceptForClasses = __VARIANT__; export const disableLegacyContextForFunctionComponents = __VARIANT__; export const disableLegacyMode = __VARIANT__; export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; -export const enableAddPropertiesFastPath = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__; export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 0caf25c155625..95a5a4c55cacd 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -19,7 +19,6 @@ export const { disableDefaultPropsExceptForClasses, disableLegacyContextForFunctionComponents, disableSchedulerTimeoutInWorkLoop, - enableAddPropertiesFastPath, enableDebugTracing, enableDeferRootSchedulingToMicrotask, enableDO_NOT_USE_disableStrictPassiveEffect, From f5b8d9378b36e7e2bb9b908752e6a9d250a44c84 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Wed, 9 Oct 2024 20:29:48 -0700 Subject: [PATCH 253/426] [Flight] Serialize top-level Date (#31163) renderModelDesctructive can sometimes be called direclty on Date values. When this happens we don't first call toJSON on the Date value so we need to explicitly handle the case where where the rendered value is a Date instance as well. This change updates renderModelDesctructive to account for sometimes receiving Date instances directly. --- .../src/__tests__/ReactFlight-test.js | 12 ++++++++++++ packages/react-server/src/ReactFlightServer.js | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 857ce99868d9b..35fe8fef0354d 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -661,6 +661,18 @@ describe('ReactFlight', () => { `); }); + it('can transport Date as a top-level value', async () => { + const date = new Date(0); + const transport = ReactNoopFlightServer.render(date); + + let readValue; + await act(async () => { + readValue = await ReactNoopFlightClient.read(transport); + }); + + expect(readValue).toEqual(date); + }); + it('can transport Error objects as values', async () => { function ComponentClient({prop}) { return ` diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 5db03d628146f..0b1a4d3c7fee1 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -1962,6 +1962,12 @@ function serializeUndefined(): string { return '$undefined'; } +function serializeDate(date: Date): string { + // JSON.stringify automatically calls Date.prototype.toJSON which calls toISOString. + // We need only tack on a $D prefix. + return '$D' + date.toJSON(); +} + function serializeDateFromDateJSON(dateJSON: string): string { // JSON.stringify automatically calls Date.prototype.toJSON which calls toISOString. // We need only tack on a $D prefix. @@ -2779,6 +2785,14 @@ function renderModelDestructive( } } + // We put the Date check low b/c most of the time Date's will already have been serialized + // before we process it in this function but when rendering a Date() as a top level it can + // end up being a Date instance here. This is rare so we deprioritize it by putting it deep + // in this function + if (value instanceof Date) { + return serializeDate(value); + } + // Verify that this is a simple plain object. const proto = getPrototypeOf(value); if ( @@ -3646,6 +3660,10 @@ function renderConsoleValue( return serializeBigInt(value); } + if (value instanceof Date) { + return serializeDate(value); + } + return 'unknown type ' + typeof value; } From 131ae818a1b4b2599d9748384e0346aaaad1fdbf Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Wed, 9 Oct 2024 22:09:14 -0700 Subject: [PATCH 254/426] [compiler][ez] Include phi identifier in AssertValidMutableRanges Summary: Looks like we accidentally skipped validating this identifier. ghstack-source-id: 05964331a812d18430b27dd90c3d5fe9dd8d65d8 Pull Request resolved: https://github.com/facebook/react/pull/31170 --- .../src/HIR/AssertValidMutableRanges.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts index 7788140ee64cc..95b11db40c90a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts @@ -20,6 +20,7 @@ import { export function assertValidMutableRanges(fn: HIRFunction): void { for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { + visitIdentifier(phi.id); for (const [, operand] of phi.operands) { visitIdentifier(operand); } From 566b0b0f14356f6e1a13722cac005c2f94f4c3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 10 Oct 2024 07:36:37 -0400 Subject: [PATCH 255/426] [Flight] Don't limit objects that are children of special types (#31160) We can't make a special getter to mark the boundary of deep serialization (which can be used for lazy loading in the future) when the parent object is a special object that we parse with getOutlinedModel. Such as Map/Set and JSX. This marks the objects that are direct children of those as not possible to limit. I don't love this solution since ideally it would maybe be more local to the serialization of a specific object. It also means that very deep trees of only Map/Set never get cut off. Maybe we should instead override the `get()` and enumeration methods on these instead somehow. It's important to have it be a getter though because that's the mechanism that lets us lazy-load more depth in the future. --- .../src/__tests__/ReactFlight-test.js | 92 +++++++++++++++++++ .../react-server/src/ReactFlightServer.js | 65 +++++++++---- 2 files changed, 140 insertions(+), 17 deletions(-) diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 35fe8fef0354d..7e1017276c976 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -3435,4 +3435,96 @@ describe('ReactFlight', () => { ); expect(caughtError.digest).toBe('digest("my-error")'); }); + + // @gate __DEV__ + it('can render deep but cut off JSX in debug info', async () => { + function createDeepJSX(n) { + if (n <= 0) { + return null; + } + return
{createDeepJSX(n - 1)}
; + } + + function ServerComponent(props) { + return
not using props
; + } + + const transport = ReactNoopFlightServer.render({ + root: ( + + {createDeepJSX(100) /* deper than objectLimit */} + + ), + }); + + await act(async () => { + const rootModel = await ReactNoopFlightClient.read(transport); + const root = rootModel.root; + const children = root._debugInfo[0].props.children; + expect(children.type).toBe('div'); + expect(children.props.children.type).toBe('div'); + ReactNoop.render(root); + }); + + expect(ReactNoop).toMatchRenderedOutput(
not using props
); + }); + + // @gate __DEV__ + it('can render deep but cut off Map/Set in debug info', async () => { + function createDeepMap(n) { + if (n <= 0) { + return null; + } + const map = new Map(); + map.set('key', createDeepMap(n - 1)); + return map; + } + + function createDeepSet(n) { + if (n <= 0) { + return null; + } + const set = new Set(); + set.add(createDeepSet(n - 1)); + return set; + } + + function ServerComponent(props) { + return
not using props
; + } + + const transport = ReactNoopFlightServer.render({ + set: ( + + ), + map: ( + + ), + }); + + await act(async () => { + const rootModel = await ReactNoopFlightClient.read(transport); + const set = rootModel.set._debugInfo[0].props.set; + const map = rootModel.map._debugInfo[0].props.map; + expect(set instanceof Set).toBe(true); + expect(set.size).toBe(1); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (const entry of set) { + expect(entry instanceof Set).toBe(true); + break; + } + + expect(map instanceof Map).toBe(true); + expect(map.size).toBe(1); + expect(map.get('key') instanceof Map).toBe(true); + + ReactNoop.render(rootModel.set); + }); + + expect(ReactNoop).toMatchRenderedOutput(
not using props
); + }); }); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 0b1a4d3c7fee1..89b785e18345a 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -137,6 +137,9 @@ import binaryToComparableString from 'shared/binaryToComparableString'; import {SuspenseException, getSuspendedThenable} from './ReactFlightThenable'; +// DEV-only set containing internal objects that should not be limited and turned into getters. +const doNotLimit: WeakSet = __DEV__ ? new WeakSet() : (null: any); + function defaultFilterStackFrame( filename: string, functionName: string, @@ -2153,6 +2156,22 @@ function serializeConsoleMap( ): string { // Like serializeMap but for renderConsoleValue. const entries = Array.from(map); + // The Map itself doesn't take up any space but the outlined object does. + counter.objectLimit++; + for (let i = 0; i < entries.length; i++) { + // Outline every object entry in case we run out of space to serialize them. + // Because we can't mark these values as limited. + const entry = entries[i]; + doNotLimit.add(entry); + const key = entry[0]; + const value = entry[1]; + if (typeof key === 'object' && key !== null) { + doNotLimit.add(key); + } + if (typeof value === 'object' && value !== null) { + doNotLimit.add(value); + } + } const id = outlineConsoleValue(request, counter, entries); return '$Q' + id.toString(16); } @@ -2164,6 +2183,16 @@ function serializeConsoleSet( ): string { // Like serializeMap but for renderConsoleValue. const entries = Array.from(set); + // The Set itself doesn't take up any space but the outlined object does. + counter.objectLimit++; + for (let i = 0; i < entries.length; i++) { + // Outline every object entry in case we run out of space to serialize them. + // Because we can't mark these values as limited. + const entry = entries[i]; + if (typeof entry === 'object' && entry !== null) { + doNotLimit.add(entry); + } + } const id = outlineConsoleValue(request, counter, entries); return '$W' + id.toString(16); } @@ -3376,20 +3405,15 @@ function renderConsoleValue( parentPropertyName: string, value: ReactClientValue, ): ReactJSONValue { - // Make sure that `parent[parentPropertyName]` wasn't JSONified before `value` was passed to us - // $FlowFixMe[incompatible-use] - const originalValue = parent[parentPropertyName]; - if ( - typeof originalValue === 'object' && - originalValue !== value && - !(originalValue instanceof Date) - ) { - } - if (value === null) { return null; } + // Special Symbol, that's very common. + if (value === REACT_ELEMENT_TYPE) { + return '$'; + } + if (typeof value === 'object') { if (isClientReference(value)) { // We actually have this value on the client so we could import it. @@ -3421,7 +3445,7 @@ function renderConsoleValue( return existingReference; } - if (counter.objectLimit <= 0) { + if (counter.objectLimit <= 0 && !doNotLimit.has(value)) { // We've reached our max number of objects to serialize across the wire so we serialize this // as a marker so that the client can error when this is accessed by the console. return serializeLimitedObject(); @@ -3441,13 +3465,12 @@ function renderConsoleValue( if (element._debugStack != null) { // Outline the debug stack so that it doesn't get cut off. debugStack = filterStackTrace(request, element._debugStack, 1); - const stackId = outlineConsoleValue( - request, - {objectLimit: debugStack.length + 2}, - debugStack, - ); - request.writtenObjects.set(debugStack, serializeByValueID(stackId)); + doNotLimit.add(debugStack); + for (let i = 0; i < debugStack.length; i++) { + doNotLimit.add(debugStack[i]); + } } + doNotLimit.add(element.props); return [ REACT_ELEMENT_TYPE, element.type, @@ -3592,6 +3615,9 @@ function renderConsoleValue( if (typeof value === 'string') { if (value[value.length - 1] === 'Z') { // Possibly a Date, whose toJSON automatically calls toISOString + // Make sure that `parent[parentPropertyName]` wasn't JSONified before `value` was passed to us + // $FlowFixMe[incompatible-use] + const originalValue = parent[parentPropertyName]; if (originalValue instanceof Date) { return serializeDateFromDateJSON(value); } @@ -3680,6 +3706,11 @@ function outlineConsoleValue( ); } + if (typeof model === 'object' && model !== null) { + // We can't limit outlined values. + doNotLimit.add(model); + } + function replacer( this: | {+[key: string | number]: ReactClientValue} From 38af456a494acb34931c71e31efbccdb53e11174 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Thu, 10 Oct 2024 06:47:32 -0700 Subject: [PATCH 256/426] [Flight] don't emit chunks for rejected thenables after abort (#31169) When aborting we emit chunks for each pending task. However there was a bug where a thenable could also reject before we could flush and we end up with an extra chunk throwing off the pendingChunks bookeeping. When a task is retried we skip it if is is not in PENDING status because we understand it was completed some other way. We need to replciate this for the reject pathway on serialized thenables since aborting if effectively completing all pending tasks and not something we need to continue to do once the thenable rejects later. --- .../src/__tests__/ReactFlightDOM-test.js | 50 +++++++++++++++++++ .../react-server/src/ReactFlightServer.js | 35 +++++++------ 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index b59eb05c7b3fb..febb5faf4ccec 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -3084,4 +3084,54 @@ describe('ReactFlightDOM', () => { , ); }); + + it('rejecting a thenable after an abort before flush should not lead to a frozen readable', async () => { + const ClientComponent = clientExports(function (props: { + promise: Promise, + }) { + return 'hello world'; + }); + + let reject; + const promise = new Promise((_, re) => { + reject = re; + }); + + function App() { + return ( +
+ + + +
+ ); + } + + const errors = []; + const {writable, readable} = getTestStream(); + const {pipe, abort} = await serverAct(() => + ReactServerDOMServer.renderToPipeableStream(, webpackMap, { + onError(x) { + errors.push(x); + }, + }), + ); + await serverAct(() => { + abort('STOP'); + reject('STOP'); + }); + pipe(writable); + + const reader = readable.getReader(); + while (true) { + const {done} = await reader.read(); + if (done) { + break; + } + } + + expect(errors).toEqual(['STOP']); + + // We expect it to get to the end here rather than hang on the reader. + }); }); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 89b785e18345a..112070d718aa3 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -696,22 +696,27 @@ function serializeThenable( pingTask(request, newTask); }, reason => { - if ( - enablePostpone && - typeof reason === 'object' && - reason !== null && - (reason: any).$$typeof === REACT_POSTPONE_TYPE - ) { - const postponeInstance: Postpone = (reason: any); - logPostpone(request, postponeInstance.message, newTask); - emitPostponeChunk(request, newTask.id, postponeInstance); - } else { - const digest = logRecoverableError(request, reason, newTask); - emitErrorChunk(request, newTask.id, digest, reason); + if (newTask.status === PENDING) { + // We expect that the only status it might be otherwise is ABORTED. + // When we abort we emit chunks in each pending task slot and don't need + // to do so again here. + if ( + enablePostpone && + typeof reason === 'object' && + reason !== null && + (reason: any).$$typeof === REACT_POSTPONE_TYPE + ) { + const postponeInstance: Postpone = (reason: any); + logPostpone(request, postponeInstance.message, newTask); + emitPostponeChunk(request, newTask.id, postponeInstance); + } else { + const digest = logRecoverableError(request, reason, newTask); + emitErrorChunk(request, newTask.id, digest, reason); + } + newTask.status = ERRORED; + request.abortableTasks.delete(newTask); + enqueueFlush(request); } - newTask.status = ERRORED; - request.abortableTasks.delete(newTask); - enqueueFlush(request); }, ); From 0f1127b552790e6dc0b65650680237ba4c94d977 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 10 Oct 2024 10:53:27 -0400 Subject: [PATCH 257/426] [prettier] Ignore compiler/target (#31168) Add missing directory to prettierignore. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31168). * #31167 * #31166 * #31165 * #31164 * #31148 * __->__ #31168 --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index ecb518e4f0f6e..7e09af76a3af8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -24,6 +24,7 @@ compiler/**/.next compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-kitchensink.js compiler/crates +compiler/target compiler/apps/playground/public compiler/**/LICENSE From b781c9f564d05c7ceaf5d8af2e26966601c0a669 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 10 Oct 2024 10:53:58 -0400 Subject: [PATCH 258/426] [compiler] Scaffold fixture library (#31148) Scaffolds an empty library to test backwards compatibility with the compiler enabled. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31148). * #31167 * #31166 * #31165 * #31164 * __->__ #31148 * #31168 --- compiler/fixtures/runtime-compat/README.md | 1 + compiler/fixtures/runtime-compat/lib/index.js | 1 + .../fixtures/runtime-compat/lib/package.json | 19 + .../fixtures/runtime-compat/lib/yarn.lock | 1670 +++++++++++++++++ 4 files changed, 1691 insertions(+) create mode 100644 compiler/fixtures/runtime-compat/README.md create mode 100644 compiler/fixtures/runtime-compat/lib/index.js create mode 100644 compiler/fixtures/runtime-compat/lib/package.json create mode 100644 compiler/fixtures/runtime-compat/lib/yarn.lock diff --git a/compiler/fixtures/runtime-compat/README.md b/compiler/fixtures/runtime-compat/README.md new file mode 100644 index 0000000000000..fea4018dfcd55 --- /dev/null +++ b/compiler/fixtures/runtime-compat/README.md @@ -0,0 +1 @@ +Reference library compiled with React Compiler. diff --git a/compiler/fixtures/runtime-compat/lib/index.js b/compiler/fixtures/runtime-compat/lib/index.js new file mode 100644 index 0000000000000..0b7dec57f53f6 --- /dev/null +++ b/compiler/fixtures/runtime-compat/lib/index.js @@ -0,0 +1 @@ +throw new Error('Not implemented yet'); diff --git a/compiler/fixtures/runtime-compat/lib/package.json b/compiler/fixtures/runtime-compat/lib/package.json new file mode 100644 index 0000000000000..e26ff7a661448 --- /dev/null +++ b/compiler/fixtures/runtime-compat/lib/package.json @@ -0,0 +1,19 @@ +{ + "name": "runtime-compat-lib", + "version": "0.0.0", + "description": "Testing ground for libraries compiled with React Compiler", + "main": "index.js", + "scripts": { + "test": "echo 'no tests'" + }, + "license": "MIT", + "devDependencies": { + "@babel/cli": "^7.25.7", + "@babel/core": "^7.25.7", + "@babel/preset-env": "^7.25.7", + "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009" + }, + "dependencies": { + "react-compiler-runtime": "0.0.0-experimental-8d8e73f-20241009" + } +} diff --git a/compiler/fixtures/runtime-compat/lib/yarn.lock b/compiler/fixtures/runtime-compat/lib/yarn.lock new file mode 100644 index 0000000000000..0e3d1b83da9e7 --- /dev/null +++ b/compiler/fixtures/runtime-compat/lib/yarn.lock @@ -0,0 +1,1670 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/cli@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.25.7.tgz#f76693c7cfb93c99844d3ed87ed4f291383ef1bf" + integrity sha512-vQw4QjrqjLSuL0Tt3gfVXbxEHOfsCcHN8tKyTclpSMYLq3Bp0BTzWYZfMKBs3PQ+to8q3BnumBIAsMdOqDJ6nw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.25" + commander "^6.2.0" + convert-source-map "^2.0.0" + fs-readdir-recursive "^1.1.0" + glob "^7.2.0" + make-dir "^2.1.0" + slash "^2.0.0" + optionalDependencies: + "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" + chokidar "^3.6.0" + +"@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== + dependencies: + "@babel/highlight" "^7.25.7" + picocolors "^1.0.0" + +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" + integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== + +"@babel/core@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" + integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" + integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== + dependencies: + "@babel/types" "^7.2.0" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== + dependencies: + "@babel/types" "^7.25.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz#63f02dbfa1f7cb75a9bdb832f300582f30bb8972" + integrity sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA== + dependencies: + "@babel/types" "^7.25.7" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz#d721650c1f595371e0a23ee816f1c3c488c0d622" + integrity sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== + dependencies: + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz#5d65074c76cae75607421c00d6bd517fe1892d6b" + integrity sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-member-expression-to-functions" "^7.25.7" + "@babel/helper-optimise-call-expression" "^7.25.7" + "@babel/helper-replace-supers" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + "@babel/traverse" "^7.25.7" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz#dcb464f0e2cdfe0c25cc2a0a59c37ab940ce894e" + integrity sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + regexpu-core "^6.1.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" + integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-member-expression-to-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz#541a33b071f0355a63a0fa4bdf9ac360116b8574" + integrity sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-optimise-call-expression@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz#1de1b99688e987af723eed44fa7fc0ee7b97d77a" + integrity sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng== + dependencies: + "@babel/types" "^7.25.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== + +"@babel/helper-remap-async-to-generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz#9efdc39df5f489bcd15533c912b6c723a0a65021" + integrity sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-wrap-function" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-replace-supers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz#38cfda3b6e990879c71d08d0fef9236b62bd75f5" + integrity sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.25.7" + "@babel/helper-optimise-call-expression" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz#382831c91038b1a6d32643f5f49505b8442cb87c" + integrity sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + +"@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== + +"@babel/helper-wrap-function@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz#9f6021dd1c4fdf4ad515c809967fc4bac9a70fe7" + integrity sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg== + dependencies: + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== + dependencies: + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" + integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== + dependencies: + "@babel/types" "^7.25.7" + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz#93969ac50ef4d68b2504b01b758af714e4cbdd64" + integrity sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz#a338d611adb9dcd599b8b1efa200c88ebeffe046" + integrity sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz#c5f755e911dfac7ef6957300c0f9c4a8c18c06f4" + integrity sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz#3b7ea04492ded990978b6deaa1dfca120ad4455a" + integrity sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + "@babel/plugin-transform-optional-chaining" "^7.25.7" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz#9622b1d597a703aa3a921e6f58c9c2d9a028d2c5" + integrity sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz#8ce248f9f4ed4b7ed4cb2e0eb4ed9efd9f52921f" + integrity sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-syntax-import-attributes@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz#d78dd0499d30df19a598e63ab895e21b909bc43f" + integrity sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz#1b9ed22e6890a0e9ff470371c73b8c749bcec386" + integrity sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-async-generator-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.7.tgz#af61a02b30d7bff5108c63bd39ac7938403426d7" + integrity sha512-4B6OhTrwYKHYYgcwErvZjbmH9X5TxQBsaBHdzEIB4l71gR5jh/tuHGlb9in47udL2+wVUcOz5XXhhfhVJwEpEg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-remap-async-to-generator" "^7.25.7" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/traverse" "^7.25.7" + +"@babel/plugin-transform-async-to-generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz#a44c7323f8d4285a6c568dd43c5c361d6367ec52" + integrity sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-remap-async-to-generator" "^7.25.7" + +"@babel/plugin-transform-block-scoped-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz#e0b8843d5571719a2f1bf7e284117a3379fcc17c" + integrity sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-block-scoping@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz#6dab95e98adf780ceef1b1c3ab0e55cd20dd410a" + integrity sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-class-properties@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz#a389cfca7a10ac80e3ff4c75fca08bd097ad1523" + integrity sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-class-static-block@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.7.tgz#d2cf3c812e3b3162d56aadf4566f45c30538cb2c" + integrity sha512-rvUUtoVlkDWtDWxGAiiQj0aNktTPn3eFynBcMC2IhsXweehwgdI9ODe+XjWw515kEmv22sSOTp/rxIRuTiB7zg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz#5103206cf80d02283bbbd044509ea3b65d0906bb" + integrity sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-replace-supers" "^7.25.7" + "@babel/traverse" "^7.25.7" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz#7f621f0aa1354b5348a935ab12e3903842466f65" + integrity sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/template" "^7.25.7" + +"@babel/plugin-transform-destructuring@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz#f6f26a9feefb5aa41fd45b6f5838901b5333d560" + integrity sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-dotall-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz#9d775c4a3ff1aea64045300fcd4309b4a610ef02" + integrity sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-duplicate-keys@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz#fbba7d1155eab76bd4f2a038cbd5d65883bd7a93" + integrity sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz#102b31608dcc22c08fbca1894e104686029dc141" + integrity sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-dynamic-import@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.7.tgz#31905ab2cfa94dcf1b1f8ce66096720b2908e518" + integrity sha512-UvcLuual4h7/GfylKm2IAA3aph9rwvAM2XBA0uPKU3lca+Maai4jBjjEVUS568ld6kJcgbouuumCBhMd/Yz17w== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz#5961a3a23a398faccd6cddb34a2182807d75fb5f" + integrity sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-export-namespace-from@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.7.tgz#beb2679db6fd3bdfe6ad6de2c8cac84a86ef2da1" + integrity sha512-h3MDAP5l34NQkkNulsTNyjdaR+OiB0Im67VU//sFupouP8Q6m9Spy7l66DcaAQxtmCqGdanPByLsnwFttxKISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz#0acfea0f27aa290818b5b48a5a44b3f03fc13669" + integrity sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + +"@babel/plugin-transform-function-name@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz#7e394ccea3693902a8b50ded8b6ae1fa7b8519fd" + integrity sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ== + dependencies: + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/plugin-transform-json-strings@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.7.tgz#6626433554aff4bd6f76a2c621a1f40e802dfb0a" + integrity sha512-Ot43PrL9TEAiCe8C/2erAjXMeVSnE/BLEx6eyrKLNFCCw5jvhTHKyHxdI1pA0kz5njZRYAnMO2KObGqOCRDYSA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz#70cbdc742f2cfdb1a63ea2cbd018d12a60b213c3" + integrity sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-logical-assignment-operators@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.7.tgz#93847feb513a1f191c5f5d903d991a0ee24fe99b" + integrity sha512-iImzbA55BjiovLyG2bggWS+V+OLkaBorNvc/yJoeeDQGztknRnDdYfp2d/UPmunZYEnZi6Lg8QcTmNMHOB0lGA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz#0a36c3fbd450cc9e6485c507f005fa3d1bc8fca5" + integrity sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-modules-amd@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz#bb4e543b5611f6c8c685a2fd485408713a3adf3d" + integrity sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA== + dependencies: + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-modules-commonjs@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz#173f0c791bb7407c092ce6d77ee90eb3f2d1d2fd" + integrity sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg== + dependencies: + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + +"@babel/plugin-transform-modules-systemjs@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz#8b14d319a177cc9c85ef8b0512afd429d9e2e60b" + integrity sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g== + dependencies: + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/plugin-transform-modules-umd@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz#00ee7a7e124289549381bfb0e24d87fd7f848367" + integrity sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw== + dependencies: + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz#a2f3f6d7f38693b462542951748f0a72a34d196d" + integrity sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-new-target@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz#52b2bde523b76c548749f38dc3054f1f45e82bc9" + integrity sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.7.tgz#0af84b86d4332654c43cf028dbdcf878b00ac168" + integrity sha512-FbuJ63/4LEL32mIxrxwYaqjJxpbzxPVQj5a+Ebrc8JICV6YX8nE53jY+K0RZT3um56GoNWgkS2BQ/uLGTjtwfw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.7.tgz#a516b78f894d1c08283f39d809b2048fd2f29448" + integrity sha512-8CbutzSSh4hmD+jJHIA8vdTNk15kAzOnFLVVgBSMGr28rt85ouT01/rezMecks9pkU939wDInImwCKv4ahU4IA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.7.tgz#fa0916521be96fd434e2db59780b24b308c6d169" + integrity sha512-1JdVKPhD7Y5PvgfFy0Mv2brdrolzpzSoUq2pr6xsR+m+3viGGeHEokFKsCgOkbeFOQxfB1Vt2F0cPJLRpFI4Zg== + dependencies: + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.25.7" + +"@babel/plugin-transform-object-super@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz#582a9cea8cf0a1e02732be5b5a703a38dedf5661" + integrity sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-replace-supers" "^7.25.7" + +"@babel/plugin-transform-optional-catch-binding@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.7.tgz#400e2d891f9288f5231694234696aa67164e4913" + integrity sha512-m9obYBA39mDPN7lJzD5WkGGb0GO54PPLXsbcnj1Hyeu8mSRz7Gb4b1A6zxNX32ZuUySDK4G6it8SDFWD1nCnqg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.7.tgz#b7f7c9321aa1d8414e67799c28d87c23682e4d68" + integrity sha512-h39agClImgPWg4H8mYVAbD1qP9vClFbEjqoJmt87Zen8pjqK8FTPUwrOXAvqu5soytwxrLMd2fx2KSCp2CHcNg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz#80c38b03ef580f6d6bffe1c5254bb35986859ac7" + integrity sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-private-methods@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz#c790a04f837b4bd61d6b0317b43aa11ff67dce80" + integrity sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-private-property-in-object@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.7.tgz#aff877efd05b57c4ad04611d8de97bf155a53369" + integrity sha512-LzA5ESzBy7tqj00Yjey9yWfs3FKy4EmJyKOSWld144OxkTji81WWnUT8nkLUn+imN/zHL8ZQlOu/MTUAhHaX3g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz#a8612b4ea4e10430f00012ecf0155662c7d6550d" + integrity sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-regenerator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz#6eb006e6d26f627bc2f7844a9f19770721ad6f3e" + integrity sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + regenerator-transform "^0.15.2" + +"@babel/plugin-transform-reserved-words@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz#dc56b25e02afaabef3ce0c5b06b0916e8523e995" + integrity sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-shorthand-properties@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz#92690a9c671915602d91533c278cc8f6bf12275f" + integrity sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-spread@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz#df83e899a9fc66284ee601a7b738568435b92998" + integrity sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + +"@babel/plugin-transform-sticky-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz#341c7002bef7f29037be7fb9684e374442dd0d17" + integrity sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-template-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz#e566c581bb16d8541dd8701093bb3457adfce16b" + integrity sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-typeof-symbol@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz#debb1287182efd20488f126be343328c679b66eb" + integrity sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-unicode-escapes@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz#973592b6d13a914794e1de8cf1383e50e0f87f81" + integrity sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-unicode-property-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz#25349197cce964b1343f74fa7cfdf791a1b1919e" + integrity sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-unicode-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz#f93a93441baf61f713b6d5552aaa856bfab34809" + integrity sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-unicode-sets-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz#d1b3295d29e0f8f4df76abc909ad1ebee919560c" + integrity sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/preset-env@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.7.tgz#fc1b092152db4b58377b85dc05c890081c1157e0" + integrity sha512-Gibz4OUdyNqqLj+7OAvBZxOD7CklCtMA5/j0JgUEwOnaRULsPDXmic2iKxL2DX2vQduPR5wH2hjZas/Vr/Oc0g== + dependencies: + "@babel/compat-data" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.7" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.7" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.25.7" + "@babel/plugin-syntax-import-attributes" "^7.25.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.25.7" + "@babel/plugin-transform-async-generator-functions" "^7.25.7" + "@babel/plugin-transform-async-to-generator" "^7.25.7" + "@babel/plugin-transform-block-scoped-functions" "^7.25.7" + "@babel/plugin-transform-block-scoping" "^7.25.7" + "@babel/plugin-transform-class-properties" "^7.25.7" + "@babel/plugin-transform-class-static-block" "^7.25.7" + "@babel/plugin-transform-classes" "^7.25.7" + "@babel/plugin-transform-computed-properties" "^7.25.7" + "@babel/plugin-transform-destructuring" "^7.25.7" + "@babel/plugin-transform-dotall-regex" "^7.25.7" + "@babel/plugin-transform-duplicate-keys" "^7.25.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.7" + "@babel/plugin-transform-dynamic-import" "^7.25.7" + "@babel/plugin-transform-exponentiation-operator" "^7.25.7" + "@babel/plugin-transform-export-namespace-from" "^7.25.7" + "@babel/plugin-transform-for-of" "^7.25.7" + "@babel/plugin-transform-function-name" "^7.25.7" + "@babel/plugin-transform-json-strings" "^7.25.7" + "@babel/plugin-transform-literals" "^7.25.7" + "@babel/plugin-transform-logical-assignment-operators" "^7.25.7" + "@babel/plugin-transform-member-expression-literals" "^7.25.7" + "@babel/plugin-transform-modules-amd" "^7.25.7" + "@babel/plugin-transform-modules-commonjs" "^7.25.7" + "@babel/plugin-transform-modules-systemjs" "^7.25.7" + "@babel/plugin-transform-modules-umd" "^7.25.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.7" + "@babel/plugin-transform-new-target" "^7.25.7" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.25.7" + "@babel/plugin-transform-numeric-separator" "^7.25.7" + "@babel/plugin-transform-object-rest-spread" "^7.25.7" + "@babel/plugin-transform-object-super" "^7.25.7" + "@babel/plugin-transform-optional-catch-binding" "^7.25.7" + "@babel/plugin-transform-optional-chaining" "^7.25.7" + "@babel/plugin-transform-parameters" "^7.25.7" + "@babel/plugin-transform-private-methods" "^7.25.7" + "@babel/plugin-transform-private-property-in-object" "^7.25.7" + "@babel/plugin-transform-property-literals" "^7.25.7" + "@babel/plugin-transform-regenerator" "^7.25.7" + "@babel/plugin-transform-reserved-words" "^7.25.7" + "@babel/plugin-transform-shorthand-properties" "^7.25.7" + "@babel/plugin-transform-spread" "^7.25.7" + "@babel/plugin-transform-sticky-regex" "^7.25.7" + "@babel/plugin-transform-template-literals" "^7.25.7" + "@babel/plugin-transform-typeof-symbol" "^7.25.7" + "@babel/plugin-transform-unicode-escapes" "^7.25.7" + "@babel/plugin-transform-unicode-property-regex" "^7.25.7" + "@babel/plugin-transform-unicode-regex" "^7.25.7" + "@babel/plugin-transform-unicode-sets-regex" "^7.25.7" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.10" + babel-plugin-polyfill-corejs3 "^0.10.6" + babel-plugin-polyfill-regenerator "^0.6.1" + core-js-compat "^3.38.1" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.8.4": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6" + integrity sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.25.7", "@babel/types@^7.4.4": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" + integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== + dependencies: + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + to-fast-properties "^2.0.0" + +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": + version "2.1.8-no-fsevents.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" + integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^13.0.0": + version "13.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" + integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== + dependencies: + "@types/yargs-parser" "*" + +ansi-regex@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +babel-plugin-polyfill-corejs2@^0.4.10: + version "0.4.11" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" + integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.6.2" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.10.6: + version "0.10.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" + integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" + core-js-compat "^3.38.0" + +babel-plugin-polyfill-regenerator@^0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" + integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.2" + +babel-plugin-react-compiler@0.0.0-experimental-58c2b1c-20241009: + version "0.0.0-experimental-58c2b1c-20241009" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-58c2b1c-20241009.tgz#a840860c5da30cbc25db0671b9c715602539a175" + integrity sha512-/DSwpfz7c1hK5dpxxlLxQJtvXCF3RjN3ZCaJ43NM4BEvzTpaS0C0jasXVBEUIFumBcdaoirFbfZkyk9htY+6Xw== + dependencies: + "@babel/generator" "7.2.0" + "@babel/types" "^7.19.0" + chalk "4" + invariant "^2.2.4" + pretty-format "^24" + zod "^3.22.4" + zod-validation-error "^2.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.23.3, browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +caniuse-lite@^1.0.30001663: + version "1.0.30001667" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" + integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== + +chalk@4: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "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== + +core-js-compat@^3.38.0, core-js-compat@^3.38.1: + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09" + integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw== + dependencies: + browserslist "^4.23.3" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +electron-to-chromium@^1.5.28: + version "1.5.35" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" + integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.2.0: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +"js-tokens@^3.0.0 || ^4.0.0", 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== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@^3.0.2, jsesc@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +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== + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash@^4.17.10: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pretty-format@^24: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + +react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: + version "0.0.0-experimental-8d8e73f-20241009" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" + integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== + +react-is@^16.8.4: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regenerate-unicode-properties@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" + integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +regenerator-transform@^0.15.2: + version "0.15.2" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" + integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpu-core@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.1.1.tgz#b469b245594cb2d088ceebc6369dceb8c00becac" + integrity sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.0" + regjsgen "^0.8.0" + regjsparser "^0.11.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.11.1.tgz#ae55c74f646db0c8fcb922d4da635e33da405149" + integrity sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ== + dependencies: + jsesc "~3.0.2" + +resolve@^1.14.2: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71" + integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +zod-validation-error@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-2.1.0.tgz#208eac75237dfed47c0018d2fe8fd03501bfc9ac" + integrity sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ== + +zod@^3.22.4: + version "3.23.8" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" + integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== From 16ac71a650d8ec9f24cd0bd6ebbe9c6d2edf9cb8 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Thu, 10 Oct 2024 17:24:51 +0200 Subject: [PATCH 259/426] Fix prepare-prerelease script (#31159) --- .../confirm-stable-version-numbers.js | 4 +- .../update-stable-version-numbers.js | 112 +++++++++--------- scripts/release/prepare-release-from-npm.js | 3 + 3 files changed, 63 insertions(+), 56 deletions(-) diff --git a/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js b/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js index dd1229634b102..0b93fba2fc12b 100644 --- a/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js +++ b/scripts/release/prepare-release-from-npm-commands/confirm-stable-version-numbers.js @@ -30,9 +30,7 @@ const run = async ({skipPackages}, versionsMap) => { let version = bestGuessVersion; if ( - skipPackages.some(skipPackageName => - packageNames.includes(skipPackageName) - ) + skipPackages.some(skipPackageName => packages.includes(skipPackageName)) ) { await confirm( theme`{spinnerSuccess ✓} Version for ${packageNames} will remain {version ${bestGuessVersion}}` diff --git a/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js b/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js index 29affd52a8299..a41d83ac69dbb 100644 --- a/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js +++ b/scripts/release/prepare-release-from-npm-commands/update-stable-version-numbers.js @@ -111,62 +111,68 @@ const run = async ({cwd, packages, version}, versionsMap) => { clear(); - // A separate "React version" is used for the embedded renderer version to support DevTools, - // since it needs to distinguish between different version ranges of React. - // We need to replace it as well as the "next" version number. - const buildInfoPath = join(nodeModulesPath, 'react', 'build-info.json'); - const {reactVersion} = await readJson(buildInfoPath); - - if (!reactVersion) { - console.error( - theme`{error Unsupported or invalid build metadata in} {path build/node_modules/react/build-info.json}` + - theme`{error . This could indicate that you have specified an outdated "next" version.}` - ); - process.exit(1); - } - - // We print the diff to the console for review, - // but it can be large so let's also write it to disk. - const diffPath = join(cwd, 'build', 'temp.diff'); - let diff = ''; - let numFilesModified = 0; - - // Find-and-replace hardcoded version (in built JS) for renderers. - for (let i = 0; i < packages.length; i++) { - const packageName = packages[i]; - const packagePath = join(nodeModulesPath, packageName); + if (packages.includes('react')) { + // A separate "React version" is used for the embedded renderer version to support DevTools, + // since it needs to distinguish between different version ranges of React. + // We need to replace it as well as the "next" version number. + const buildInfoPath = join(nodeModulesPath, 'react', 'build-info.json'); + const {reactVersion} = await readJson(buildInfoPath); + + if (!reactVersion) { + console.error( + theme`{error Unsupported or invalid build metadata in} {path build/node_modules/react/build-info.json}` + + theme`{error . This could indicate that you have specified an outdated "next" version.}` + ); + process.exit(1); + } - let files = await execRead( - `find ${packagePath} -name '*.js' -exec echo {} \\;`, - {cwd} + // We print the diff to the console for review, + // but it can be large so let's also write it to disk. + const diffPath = join(cwd, 'build', 'temp.diff'); + let diff = ''; + let numFilesModified = 0; + + // Find-and-replace hardcoded version (in built JS) for renderers. + for (let i = 0; i < packages.length; i++) { + const packageName = packages[i]; + const packagePath = join(nodeModulesPath, packageName); + + let files = await execRead( + `find ${packagePath} -name '*.js' -exec echo {} \\;`, + {cwd} + ); + files = files.split('\n'); + files.forEach(path => { + const newStableVersion = versionsMap.get(packageName); + const beforeContents = readFileSync(path, 'utf8', {cwd}); + let afterContents = beforeContents; + // Replace all "next" version numbers (e.g. header @license). + while (afterContents.indexOf(version) >= 0) { + afterContents = afterContents.replace(version, newStableVersion); + } + // Replace inline renderer version numbers (e.g. shared/ReactVersion). + while (afterContents.indexOf(reactVersion) >= 0) { + afterContents = afterContents.replace(reactVersion, newStableVersion); + } + if (beforeContents !== afterContents) { + numFilesModified++; + // Using a relative path for diff helps with the snapshot test + diff += printDiff(relative(cwd, path), beforeContents, afterContents); + writeFileSync(path, afterContents, {cwd}); + } + }); + } + writeFileSync(diffPath, diff, {cwd}); + console.log(theme.header(`\n${numFilesModified} files have been updated.`)); + console.log( + theme`A full diff is available at {path ${relative(cwd, diffPath)}}.` + ); + await confirm('Do the changes above look correct?'); + } else { + console.log( + theme`Skipping React renderer version update because React is not included in the release.` ); - files = files.split('\n'); - files.forEach(path => { - const newStableVersion = versionsMap.get(packageName); - const beforeContents = readFileSync(path, 'utf8', {cwd}); - let afterContents = beforeContents; - // Replace all "next" version numbers (e.g. header @license). - while (afterContents.indexOf(version) >= 0) { - afterContents = afterContents.replace(version, newStableVersion); - } - // Replace inline renderer version numbers (e.g. shared/ReactVersion). - while (afterContents.indexOf(reactVersion) >= 0) { - afterContents = afterContents.replace(reactVersion, newStableVersion); - } - if (beforeContents !== afterContents) { - numFilesModified++; - // Using a relative path for diff helps with the snapshot test - diff += printDiff(relative(cwd, path), beforeContents, afterContents); - writeFileSync(path, afterContents, {cwd}); - } - }); } - writeFileSync(diffPath, diff, {cwd}); - console.log(theme.header(`\n${numFilesModified} files have been updated.`)); - console.log( - theme`A full diff is available at {path ${relative(cwd, diffPath)}}.` - ); - await confirm('Do the changes above look correct?'); clear(); }; diff --git a/scripts/release/prepare-release-from-npm.js b/scripts/release/prepare-release-from-npm.js index faada23d2bd75..e23ffb39bc1c0 100755 --- a/scripts/release/prepare-release-from-npm.js +++ b/scripts/release/prepare-release-from-npm.js @@ -27,6 +27,9 @@ const run = async () => { } params.packages = await getPublicPackages(isExperimental); + params.packages = params.packages.filter(packageName => { + return !params.skipPackages.includes(packageName); + }); // Map of package name to upcoming stable version. // This Map is initially populated with guesses based on local versions. From 2ef407937b724a3af5b8ca4d082ecee5005d731b Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 10 Oct 2024 11:33:02 -0400 Subject: [PATCH 260/426] [compiler] Scaffold fixture apps (#31164) Scaffold empty apps to consume the fixture lib. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31164). * #31167 * #31166 * #31165 * __->__ #31164 * #31148 * #31168 --- .../fixtures/runtime-compat/app-18/.gitignore | 24 + .../fixtures/runtime-compat/app-18/README.md | 50 + .../runtime-compat/app-18/eslint.config.js | 28 + .../fixtures/runtime-compat/app-18/index.html | 13 + .../runtime-compat/app-18/package.json | 29 + .../runtime-compat/app-18/public/vite.svg | 1 + .../runtime-compat/app-18/src/App.css | 42 + .../runtime-compat/app-18/src/App.tsx | 35 + .../app-18/src/assets/react.svg | 1 + .../runtime-compat/app-18/src/index.css | 68 + .../runtime-compat/app-18/src/main.tsx | 10 + .../runtime-compat/app-18/src/vite-env.d.ts | 1 + .../runtime-compat/app-18/tsconfig.app.json | 24 + .../runtime-compat/app-18/tsconfig.json | 7 + .../runtime-compat/app-18/tsconfig.node.json | 22 + .../runtime-compat/app-18/vite.config.ts | 7 + .../fixtures/runtime-compat/app-18/yarn.lock | 1550 +++++++++++++++++ .../fixtures/runtime-compat/app-19/.gitignore | 24 + .../fixtures/runtime-compat/app-19/README.md | 50 + .../runtime-compat/app-19/eslint.config.js | 28 + .../fixtures/runtime-compat/app-19/index.html | 13 + .../runtime-compat/app-19/package.json | 29 + .../runtime-compat/app-19/public/vite.svg | 1 + .../runtime-compat/app-19/src/App.css | 42 + .../runtime-compat/app-19/src/App.tsx | 35 + .../app-19/src/assets/react.svg | 1 + .../runtime-compat/app-19/src/index.css | 68 + .../runtime-compat/app-19/src/main.tsx | 10 + .../runtime-compat/app-19/src/vite-env.d.ts | 1 + .../runtime-compat/app-19/tsconfig.app.json | 24 + .../runtime-compat/app-19/tsconfig.json | 7 + .../runtime-compat/app-19/tsconfig.node.json | 22 + .../runtime-compat/app-19/vite.config.ts | 7 + .../fixtures/runtime-compat/app-19/yarn.lock | 1538 ++++++++++++++++ compiler/fixtures/runtime-compat/setup.sh | 13 + 35 files changed, 3825 insertions(+) create mode 100644 compiler/fixtures/runtime-compat/app-18/.gitignore create mode 100644 compiler/fixtures/runtime-compat/app-18/README.md create mode 100644 compiler/fixtures/runtime-compat/app-18/eslint.config.js create mode 100644 compiler/fixtures/runtime-compat/app-18/index.html create mode 100644 compiler/fixtures/runtime-compat/app-18/package.json create mode 100644 compiler/fixtures/runtime-compat/app-18/public/vite.svg create mode 100644 compiler/fixtures/runtime-compat/app-18/src/App.css create mode 100644 compiler/fixtures/runtime-compat/app-18/src/App.tsx create mode 100644 compiler/fixtures/runtime-compat/app-18/src/assets/react.svg create mode 100644 compiler/fixtures/runtime-compat/app-18/src/index.css create mode 100644 compiler/fixtures/runtime-compat/app-18/src/main.tsx create mode 100644 compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts create mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.app.json create mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.json create mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.node.json create mode 100644 compiler/fixtures/runtime-compat/app-18/vite.config.ts create mode 100644 compiler/fixtures/runtime-compat/app-18/yarn.lock create mode 100644 compiler/fixtures/runtime-compat/app-19/.gitignore create mode 100644 compiler/fixtures/runtime-compat/app-19/README.md create mode 100644 compiler/fixtures/runtime-compat/app-19/eslint.config.js create mode 100644 compiler/fixtures/runtime-compat/app-19/index.html create mode 100644 compiler/fixtures/runtime-compat/app-19/package.json create mode 100644 compiler/fixtures/runtime-compat/app-19/public/vite.svg create mode 100644 compiler/fixtures/runtime-compat/app-19/src/App.css create mode 100644 compiler/fixtures/runtime-compat/app-19/src/App.tsx create mode 100644 compiler/fixtures/runtime-compat/app-19/src/assets/react.svg create mode 100644 compiler/fixtures/runtime-compat/app-19/src/index.css create mode 100644 compiler/fixtures/runtime-compat/app-19/src/main.tsx create mode 100644 compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts create mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.app.json create mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.json create mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.node.json create mode 100644 compiler/fixtures/runtime-compat/app-19/vite.config.ts create mode 100644 compiler/fixtures/runtime-compat/app-19/yarn.lock create mode 100755 compiler/fixtures/runtime-compat/setup.sh diff --git a/compiler/fixtures/runtime-compat/app-18/.gitignore b/compiler/fixtures/runtime-compat/app-18/.gitignore new file mode 100644 index 0000000000000..a547bf36d8d11 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/compiler/fixtures/runtime-compat/app-18/README.md b/compiler/fixtures/runtime-compat/app-18/README.md new file mode 100644 index 0000000000000..74872fd4af60f --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/README.md @@ -0,0 +1,50 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/compiler/fixtures/runtime-compat/app-18/eslint.config.js b/compiler/fixtures/runtime-compat/app-18/eslint.config.js new file mode 100644 index 0000000000000..c6d2eb5006ea4 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + {ignores: ['dist']}, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + {allowConstantExport: true}, + ], + }, + } +); diff --git a/compiler/fixtures/runtime-compat/app-18/index.html b/compiler/fixtures/runtime-compat/app-18/index.html new file mode 100644 index 0000000000000..e4b78eae12304 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/compiler/fixtures/runtime-compat/app-18/package.json b/compiler/fixtures/runtime-compat/app-18/package.json new file mode 100644 index 0000000000000..c842bd49131bf --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/package.json @@ -0,0 +1,29 @@ +{ + "name": "app-18", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@eslint/js": "^9.11.1", + "@types/react": "^18.3.10", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.2", + "eslint": "^9.11.1", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.12", + "globals": "^15.9.0", + "typescript": "^5.5.3", + "typescript-eslint": "^8.7.0", + "vite": "^5.4.8" + } +} diff --git a/compiler/fixtures/runtime-compat/app-18/public/vite.svg b/compiler/fixtures/runtime-compat/app-18/public/vite.svg new file mode 100644 index 0000000000000..e7b8dfb1b2a60 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/src/App.css b/compiler/fixtures/runtime-compat/app-18/src/App.css new file mode 100644 index 0000000000000..b9d355df2a595 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/compiler/fixtures/runtime-compat/app-18/src/App.tsx b/compiler/fixtures/runtime-compat/app-18/src/App.tsx new file mode 100644 index 0000000000000..7bc88a7614856 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/src/App.tsx @@ -0,0 +1,35 @@ +import {useState} from 'react'; +import reactLogo from './assets/react.svg'; +import viteLogo from '/vite.svg'; +import './App.css'; + +function App() { + const [count, setCount] = useState(0); + + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ); +} + +export default App; diff --git a/compiler/fixtures/runtime-compat/app-18/src/assets/react.svg b/compiler/fixtures/runtime-compat/app-18/src/assets/react.svg new file mode 100644 index 0000000000000..6c87de9bb3358 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/src/index.css b/compiler/fixtures/runtime-compat/app-18/src/index.css new file mode 100644 index 0000000000000..6119ad9a8faaa --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/compiler/fixtures/runtime-compat/app-18/src/main.tsx b/compiler/fixtures/runtime-compat/app-18/src/main.tsx new file mode 100644 index 0000000000000..080dac371e6d8 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/src/main.tsx @@ -0,0 +1,10 @@ +import {StrictMode} from 'react'; +import {createRoot} from 'react-dom/client'; +import App from './App.tsx'; +import './index.css'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts b/compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts new file mode 100644 index 0000000000000..11f02fe2a0061 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.app.json b/compiler/fixtures/runtime-compat/app-18/tsconfig.app.json new file mode 100644 index 0000000000000..f0a235055d246 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.json b/compiler/fixtures/runtime-compat/app-18/tsconfig.json new file mode 100644 index 0000000000000..1ffef600d959e --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.node.json b/compiler/fixtures/runtime-compat/app-18/tsconfig.node.json new file mode 100644 index 0000000000000..0d3d71446a455 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/tsconfig.node.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/compiler/fixtures/runtime-compat/app-18/vite.config.ts b/compiler/fixtures/runtime-compat/app-18/vite.config.ts new file mode 100644 index 0000000000000..f4f509bd78512 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/vite.config.ts @@ -0,0 +1,7 @@ +import {defineConfig} from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/compiler/fixtures/runtime-compat/app-18/yarn.lock b/compiler/fixtures/runtime-compat/app-18/yarn.lock new file mode 100644 index 0000000000000..6023f48713b9f --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/yarn.lock @@ -0,0 +1,1550 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== + dependencies: + "@babel/highlight" "^7.25.7" + picocolors "^1.0.0" + +"@babel/compat-data@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" + integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== + +"@babel/core@^7.25.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" + integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== + dependencies: + "@babel/types" "^7.25.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== + dependencies: + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-plugin-utils@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== + +"@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + +"@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== + +"@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== + dependencies: + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" + integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== + dependencies: + "@babel/types" "^7.25.7" + +"@babel/plugin-transform-react-jsx-self@^7.24.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz#3d11df143131fd8f5486a1f7d3839890f88f8c85" + integrity sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-react-jsx-source@^7.24.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz#a0d8372310d5ea5b0447dfa03a8485f960eff7be" + integrity sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/template@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" + integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== + dependencies: + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + to-fast-properties "^2.0.0" + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.12.0", "@eslint/js@^9.11.1": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" + integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== + dependencies: + levn "^0.4.1" + +"@humanfs/core@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" + integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== + +"@humanfs/node@^0.16.5": + version "0.16.5" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" + integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== + dependencies: + "@humanfs/core" "^0.19.0" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@rollup/rollup-android-arm-eabi@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" + integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== + +"@rollup/rollup-android-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" + integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== + +"@rollup/rollup-darwin-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" + integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== + +"@rollup/rollup-darwin-x64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" + integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" + integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== + +"@rollup/rollup-linux-arm-musleabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" + integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== + +"@rollup/rollup-linux-arm64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" + integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== + +"@rollup/rollup-linux-arm64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" + integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" + integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== + +"@rollup/rollup-linux-riscv64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" + integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== + +"@rollup/rollup-linux-s390x-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" + integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== + +"@rollup/rollup-linux-x64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" + integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== + +"@rollup/rollup-linux-x64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" + integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== + +"@rollup/rollup-win32-arm64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" + integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== + +"@rollup/rollup-win32-ia32-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" + integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== + +"@rollup/rollup-win32-x64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" + integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/estree@1.0.6", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/prop-types@*": + version "15.7.13" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== + +"@types/react-dom@^18.3.0": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.3.10": + version "18.3.11" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.11.tgz#9d530601ff843ee0d7030d4227ea4360236bd537" + integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@typescript-eslint/eslint-plugin@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" + integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/type-utils" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" + integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== + dependencies: + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" + integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + +"@typescript-eslint/type-utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" + integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== + dependencies: + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" + integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== + +"@typescript-eslint/typescript-estree@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" + integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" + integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + +"@typescript-eslint/visitor-keys@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" + integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== + dependencies: + "@typescript-eslint/types" "8.8.1" + eslint-visitor-keys "^3.4.3" + +"@vitejs/plugin-react@^4.3.2": + version "4.3.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz#1e13f666fe3135b477220d3c13b783704636b6e4" + integrity sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg== + dependencies: + "@babel/core" "^7.25.2" + "@babel/plugin-transform-react-jsx-self" "^7.24.7" + "@babel/plugin-transform-react-jsx-source" "^7.24.7" + "@types/babel__core" "^7.20.5" + react-refresh "^0.14.2" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.12.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +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== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +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.30001663: + version "1.0.30001667" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" + integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "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== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +electron-to-chromium@^1.5.28: + version "1.5.35" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" + integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-plugin-react-hooks@^5.1.0-rc.0: + version "5.1.0-rc-fb9a90fa48-20240614" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz#206a7ec005f0b286aaf7091f4e566083d310b189" + integrity sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w== + +eslint-plugin-react-refresh@^0.4.12: + version "0.4.12" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz#73d61c7fcbe3f7280edb6579380b4350d2f547ed" + integrity sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg== + +eslint-scope@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" + integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" + integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== + +eslint@^9.11.1: + version "9.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" + integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.12.0" + "@eslint/plugin-kit" "^0.2.0" + "@humanfs/node" "^0.16.5" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.1.0" + eslint-visitor-keys "^4.1.0" + espree "^10.2.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + text-table "^0.2.0" + +espree@^10.0.1, espree@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" + integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== + dependencies: + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.1.0" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^15.9.0: + version "15.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e" + integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + 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" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +"js-tokens@^3.0.0 || ^4.0.0", 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.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +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== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +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" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +postcss@^8.4.43: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.0" + source-map-js "^1.2.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-dom@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.2" + +react-refresh@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" + integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== + +react@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== + dependencies: + loose-envify "^1.1.0" + +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== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rollup@^4.20.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" + integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.24.0" + "@rollup/rollup-android-arm64" "4.24.0" + "@rollup/rollup-darwin-arm64" "4.24.0" + "@rollup/rollup-darwin-x64" "4.24.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" + "@rollup/rollup-linux-arm-musleabihf" "4.24.0" + "@rollup/rollup-linux-arm64-gnu" "4.24.0" + "@rollup/rollup-linux-arm64-musl" "4.24.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" + "@rollup/rollup-linux-riscv64-gnu" "4.24.0" + "@rollup/rollup-linux-s390x-gnu" "4.24.0" + "@rollup/rollup-linux-x64-gnu" "4.24.0" + "@rollup/rollup-linux-x64-musl" "4.24.0" + "@rollup/rollup-win32-arm64-msvc" "4.24.0" + "@rollup/rollup-win32-ia32-msvc" "4.24.0" + "@rollup/rollup-win32-x64-msvc" "4.24.0" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +scheduler@^0.23.2: + version "0.23.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== + dependencies: + loose-envify "^1.1.0" + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +typescript-eslint@^8.7.0: + version "8.8.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a" + integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.8.1" + "@typescript-eslint/parser" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + +typescript@^5.5.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +vite@^5.4.8: + version "5.4.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8" + integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/compiler/fixtures/runtime-compat/app-19/.gitignore b/compiler/fixtures/runtime-compat/app-19/.gitignore new file mode 100644 index 0000000000000..a547bf36d8d11 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/compiler/fixtures/runtime-compat/app-19/README.md b/compiler/fixtures/runtime-compat/app-19/README.md new file mode 100644 index 0000000000000..74872fd4af60f --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/README.md @@ -0,0 +1,50 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/compiler/fixtures/runtime-compat/app-19/eslint.config.js b/compiler/fixtures/runtime-compat/app-19/eslint.config.js new file mode 100644 index 0000000000000..c6d2eb5006ea4 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import reactHooks from 'eslint-plugin-react-hooks'; +import reactRefresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + {ignores: ['dist']}, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + {allowConstantExport: true}, + ], + }, + } +); diff --git a/compiler/fixtures/runtime-compat/app-19/index.html b/compiler/fixtures/runtime-compat/app-19/index.html new file mode 100644 index 0000000000000..e4b78eae12304 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/compiler/fixtures/runtime-compat/app-19/package.json b/compiler/fixtures/runtime-compat/app-19/package.json new file mode 100644 index 0000000000000..d75d69a5569d0 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/package.json @@ -0,0 +1,29 @@ +{ + "name": "app-19", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "19.0.0-beta-26f2496093-20240514", + "react-dom": "19.0.0-beta-26f2496093-20240514" + }, + "devDependencies": { + "@eslint/js": "^9.11.1", + "@types/react": "^18.3.10", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.2", + "eslint": "^9.11.1", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.12", + "globals": "^15.9.0", + "typescript": "^5.5.3", + "typescript-eslint": "^8.7.0", + "vite": "^5.4.8" + } +} diff --git a/compiler/fixtures/runtime-compat/app-19/public/vite.svg b/compiler/fixtures/runtime-compat/app-19/public/vite.svg new file mode 100644 index 0000000000000..e7b8dfb1b2a60 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/src/App.css b/compiler/fixtures/runtime-compat/app-19/src/App.css new file mode 100644 index 0000000000000..b9d355df2a595 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/compiler/fixtures/runtime-compat/app-19/src/App.tsx b/compiler/fixtures/runtime-compat/app-19/src/App.tsx new file mode 100644 index 0000000000000..7bc88a7614856 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/src/App.tsx @@ -0,0 +1,35 @@ +import {useState} from 'react'; +import reactLogo from './assets/react.svg'; +import viteLogo from '/vite.svg'; +import './App.css'; + +function App() { + const [count, setCount] = useState(0); + + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ); +} + +export default App; diff --git a/compiler/fixtures/runtime-compat/app-19/src/assets/react.svg b/compiler/fixtures/runtime-compat/app-19/src/assets/react.svg new file mode 100644 index 0000000000000..6c87de9bb3358 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/src/index.css b/compiler/fixtures/runtime-compat/app-19/src/index.css new file mode 100644 index 0000000000000..6119ad9a8faaa --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/compiler/fixtures/runtime-compat/app-19/src/main.tsx b/compiler/fixtures/runtime-compat/app-19/src/main.tsx new file mode 100644 index 0000000000000..080dac371e6d8 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/src/main.tsx @@ -0,0 +1,10 @@ +import {StrictMode} from 'react'; +import {createRoot} from 'react-dom/client'; +import App from './App.tsx'; +import './index.css'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts b/compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts new file mode 100644 index 0000000000000..11f02fe2a0061 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.app.json b/compiler/fixtures/runtime-compat/app-19/tsconfig.app.json new file mode 100644 index 0000000000000..f0a235055d246 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.json b/compiler/fixtures/runtime-compat/app-19/tsconfig.json new file mode 100644 index 0000000000000..1ffef600d959e --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.node.json b/compiler/fixtures/runtime-compat/app-19/tsconfig.node.json new file mode 100644 index 0000000000000..0d3d71446a455 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/tsconfig.node.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/compiler/fixtures/runtime-compat/app-19/vite.config.ts b/compiler/fixtures/runtime-compat/app-19/vite.config.ts new file mode 100644 index 0000000000000..f4f509bd78512 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/vite.config.ts @@ -0,0 +1,7 @@ +import {defineConfig} from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); diff --git a/compiler/fixtures/runtime-compat/app-19/yarn.lock b/compiler/fixtures/runtime-compat/app-19/yarn.lock new file mode 100644 index 0000000000000..3e6ef0621a606 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/yarn.lock @@ -0,0 +1,1538 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== + dependencies: + "@babel/highlight" "^7.25.7" + picocolors "^1.0.0" + +"@babel/compat-data@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" + integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== + +"@babel/core@^7.25.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" + integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== + dependencies: + "@babel/types" "^7.25.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== + dependencies: + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-plugin-utils@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== + +"@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + +"@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== + +"@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== + dependencies: + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" + integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== + dependencies: + "@babel/types" "^7.25.7" + +"@babel/plugin-transform-react-jsx-self@^7.24.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz#3d11df143131fd8f5486a1f7d3839890f88f8c85" + integrity sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/plugin-transform-react-jsx-source@^7.24.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz#a0d8372310d5ea5b0447dfa03a8485f960eff7be" + integrity sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + +"@babel/template@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" + integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== + dependencies: + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + to-fast-properties "^2.0.0" + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.12.0", "@eslint/js@^9.11.1": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" + integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== + dependencies: + levn "^0.4.1" + +"@humanfs/core@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" + integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== + +"@humanfs/node@^0.16.5": + version "0.16.5" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" + integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== + dependencies: + "@humanfs/core" "^0.19.0" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@rollup/rollup-android-arm-eabi@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" + integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== + +"@rollup/rollup-android-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" + integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== + +"@rollup/rollup-darwin-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" + integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== + +"@rollup/rollup-darwin-x64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" + integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" + integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== + +"@rollup/rollup-linux-arm-musleabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" + integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== + +"@rollup/rollup-linux-arm64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" + integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== + +"@rollup/rollup-linux-arm64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" + integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" + integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== + +"@rollup/rollup-linux-riscv64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" + integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== + +"@rollup/rollup-linux-s390x-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" + integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== + +"@rollup/rollup-linux-x64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" + integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== + +"@rollup/rollup-linux-x64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" + integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== + +"@rollup/rollup-win32-arm64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" + integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== + +"@rollup/rollup-win32-ia32-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" + integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== + +"@rollup/rollup-win32-x64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" + integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== + +"@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/estree@1.0.6", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/prop-types@*": + version "15.7.13" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" + integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== + +"@types/react-dom@^18.3.0": + version "18.3.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^18.3.10": + version "18.3.11" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.11.tgz#9d530601ff843ee0d7030d4227ea4360236bd537" + integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + +"@typescript-eslint/eslint-plugin@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" + integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/type-utils" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" + integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== + dependencies: + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" + integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + +"@typescript-eslint/type-utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" + integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== + dependencies: + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" + integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== + +"@typescript-eslint/typescript-estree@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" + integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== + dependencies: + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" + integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + +"@typescript-eslint/visitor-keys@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" + integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== + dependencies: + "@typescript-eslint/types" "8.8.1" + eslint-visitor-keys "^3.4.3" + +"@vitejs/plugin-react@^4.3.2": + version "4.3.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz#1e13f666fe3135b477220d3c13b783704636b6e4" + integrity sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg== + dependencies: + "@babel/core" "^7.25.2" + "@babel/plugin-transform-react-jsx-self" "^7.24.7" + "@babel/plugin-transform-react-jsx-source" "^7.24.7" + "@types/babel__core" "^7.20.5" + react-refresh "^0.14.2" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.12.0: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +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== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +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.30001663: + version "1.0.30001667" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" + integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "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== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +csstype@^3.0.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== + +debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +electron-to-chromium@^1.5.28: + version "1.5.35" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" + integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-plugin-react-hooks@^5.1.0-rc.0: + version "5.1.0-rc-fb9a90fa48-20240614" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz#206a7ec005f0b286aaf7091f4e566083d310b189" + integrity sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w== + +eslint-plugin-react-refresh@^0.4.12: + version "0.4.12" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz#73d61c7fcbe3f7280edb6579380b4350d2f547ed" + integrity sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg== + +eslint-scope@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" + integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" + integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== + +eslint@^9.11.1: + version "9.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" + integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.12.0" + "@eslint/plugin-kit" "^0.2.0" + "@humanfs/node" "^0.16.5" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.1.0" + eslint-visitor-keys "^4.1.0" + espree "^10.2.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + text-table "^0.2.0" + +espree@^10.0.1, espree@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" + integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== + dependencies: + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.1.0" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^15.9.0: + version "15.11.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e" + integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + 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" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +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.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +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== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +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" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +postcss@^8.4.43: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.0" + source-map-js "^1.2.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-dom@19.0.0-beta-26f2496093-20240514: + version "19.0.0-beta-26f2496093-20240514" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-26f2496093-20240514.tgz#5fe4e829db8d379303057f539900a61ed6ca2615" + integrity sha512-UvQ+K1l3DFQ34LDgfFSNuUGi9EC+yfE9tS6MdpNTd5fx7qC7KLfepfC/KpxWMQZ7JfE3axD4ZO6H4cBSpAZpqw== + dependencies: + scheduler "0.25.0-beta-26f2496093-20240514" + +react-refresh@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" + integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== + +react@19.0.0-beta-26f2496093-20240514: + version "19.0.0-beta-26f2496093-20240514" + resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-beta-26f2496093-20240514.tgz#3a0d63746b3f9ebd461a0731191bd08047fb1dbb" + integrity sha512-ZsU/WjNZ6GfzMWsq2DcGjElpV9it8JmETHm9mAJuOJNhuJcWJxt8ltCJabONFRpDFq1A/DP0d0KFj9CTJVM4VA== + +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== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rollup@^4.20.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" + integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.24.0" + "@rollup/rollup-android-arm64" "4.24.0" + "@rollup/rollup-darwin-arm64" "4.24.0" + "@rollup/rollup-darwin-x64" "4.24.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" + "@rollup/rollup-linux-arm-musleabihf" "4.24.0" + "@rollup/rollup-linux-arm64-gnu" "4.24.0" + "@rollup/rollup-linux-arm64-musl" "4.24.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" + "@rollup/rollup-linux-riscv64-gnu" "4.24.0" + "@rollup/rollup-linux-s390x-gnu" "4.24.0" + "@rollup/rollup-linux-x64-gnu" "4.24.0" + "@rollup/rollup-linux-x64-musl" "4.24.0" + "@rollup/rollup-win32-arm64-msvc" "4.24.0" + "@rollup/rollup-win32-ia32-msvc" "4.24.0" + "@rollup/rollup-win32-x64-msvc" "4.24.0" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +scheduler@0.25.0-beta-26f2496093-20240514: + version "0.25.0-beta-26f2496093-20240514" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-26f2496093-20240514.tgz#a3bc0ff694ec6de7a78c1e48e1f8f4a8555bd77d" + integrity sha512-vDwOytLHFnA3SW2B1lNcbO+/qKVyLCX+KLpm+tRGNDsXpyxzRgkIaYGWmX+S70AJGchUHCtuqQ50GFeFgDbXUw== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +typescript-eslint@^8.7.0: + version "8.8.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a" + integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.8.1" + "@typescript-eslint/parser" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + +typescript@^5.5.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +vite@^5.4.8: + version "5.4.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8" + integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/compiler/fixtures/runtime-compat/setup.sh b/compiler/fixtures/runtime-compat/setup.sh new file mode 100755 index 0000000000000..c1cd6dc09b60e --- /dev/null +++ b/compiler/fixtures/runtime-compat/setup.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# 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. + +set -eo pipefail + +HERE=$(pwd) + +cd lib && yarn --silent link +cd $HERE/app-18 && yarn --silent link runtime-compat-lib +cd $HERE/app-19 && yarn --silent link runtime-compat-lib From eb0e265cd9dbf3ebcabac52664beefdf64389ad0 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 10 Oct 2024 11:39:42 -0400 Subject: [PATCH 261/426] [compiler] Compile lib (#31165) Add and compile a simple hook with rollup and babel. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31165). * #31167 * #31166 * __->__ #31165 --- .../runtime-compat/lib/babel.config.js | 10 + compiler/fixtures/runtime-compat/lib/index.js | 14 +- .../fixtures/runtime-compat/lib/package.json | 17 +- .../runtime-compat/lib/rollup.config.js | 51 ++ .../fixtures/runtime-compat/lib/yarn.lock | 553 +++++++++++++++++- 5 files changed, 638 insertions(+), 7 deletions(-) create mode 100644 compiler/fixtures/runtime-compat/lib/babel.config.js create mode 100644 compiler/fixtures/runtime-compat/lib/rollup.config.js diff --git a/compiler/fixtures/runtime-compat/lib/babel.config.js b/compiler/fixtures/runtime-compat/lib/babel.config.js new file mode 100644 index 0000000000000..7c4be358783ba --- /dev/null +++ b/compiler/fixtures/runtime-compat/lib/babel.config.js @@ -0,0 +1,10 @@ +const plugins = [ + [ + 'babel-plugin-react-compiler', + { + target: '18', + }, + ], +]; + +module.exports = {plugins}; diff --git a/compiler/fixtures/runtime-compat/lib/index.js b/compiler/fixtures/runtime-compat/lib/index.js index 0b7dec57f53f6..063ce1362d9f0 100644 --- a/compiler/fixtures/runtime-compat/lib/index.js +++ b/compiler/fixtures/runtime-compat/lib/index.js @@ -1 +1,13 @@ -throw new Error('Not implemented yet'); +import {useState, useEffect} from 'react'; + +export function useTime() { + const [time, setTime] = useState(() => new Date()); + useEffect(() => { + const id = setInterval(() => { + setTime(new Date()); + }, 1000); + return () => clearInterval(id); + }, []); + + return time; +} diff --git a/compiler/fixtures/runtime-compat/lib/package.json b/compiler/fixtures/runtime-compat/lib/package.json index e26ff7a661448..ed8cb7b821ad3 100644 --- a/compiler/fixtures/runtime-compat/lib/package.json +++ b/compiler/fixtures/runtime-compat/lib/package.json @@ -2,8 +2,9 @@ "name": "runtime-compat-lib", "version": "0.0.0", "description": "Testing ground for libraries compiled with React Compiler", - "main": "index.js", + "main": "dist/index.js", "scripts": { + "build": "rimraf dist && rollup --config --bundleConfigAsCjs", "test": "echo 'no tests'" }, "license": "MIT", @@ -11,9 +12,21 @@ "@babel/cli": "^7.25.7", "@babel/core": "^7.25.7", "@babel/preset-env": "^7.25.7", - "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009" + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-json": "^6.1.0", + "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009", + "@rollup/plugin-terser": "^0.4.4", + "react": "19.0.0-beta-26f2496093-20240514", + "react-dom": "19.0.0-beta-26f2496093-20240514", + "rimraf": "5", + "rollup": "^4.22.4", + "rollup-plugin-banner2": "^1.2.3", + "rollup-plugin-prettier": "^4.1.1" }, "dependencies": { "react-compiler-runtime": "0.0.0-experimental-8d8e73f-20241009" + }, + "peerDependencies": { + "react": "^18 || ^19" } } diff --git a/compiler/fixtures/runtime-compat/lib/rollup.config.js b/compiler/fixtures/runtime-compat/lib/rollup.config.js new file mode 100644 index 0000000000000..f5b2c221ed2f3 --- /dev/null +++ b/compiler/fixtures/runtime-compat/lib/rollup.config.js @@ -0,0 +1,51 @@ +/** + * 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 json from '@rollup/plugin-json'; +import terser from '@rollup/plugin-terser'; +import prettier from 'rollup-plugin-prettier'; +import banner2 from 'rollup-plugin-banner2'; +import babel from '@rollup/plugin-babel'; + +const ROLLUP_CONFIG = { + input: 'index.js', + output: { + file: 'dist/index.js', + format: 'esm', + sourcemap: false, + exports: 'named', + }, + plugins: [ + json(), + babel({babelHelpers: 'bundled'}), + terser({ + format: { + comments: false, + }, + compress: false, + mangle: false, + }), + prettier(), + banner2( + () => `/** + * 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. + * + * @lightSyntaxTransform + * @noflow + * @nolint + * @preventMunge + * @preserve-invariant-messages + */ +` + ), + ], +}; + +export default ROLLUP_CONFIG; diff --git a/compiler/fixtures/runtime-compat/lib/yarn.lock b/compiler/fixtures/runtime-compat/lib/yarn.lock index 0e3d1b83da9e7..fee616b98adbe 100644 --- a/compiler/fixtures/runtime-compat/lib/yarn.lock +++ b/compiler/fixtures/runtime-compat/lib/yarn.lock @@ -148,7 +148,7 @@ "@babel/traverse" "^7.25.7" "@babel/types" "^7.25.7" -"@babel/helper-module-imports@^7.25.7": +"@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== @@ -961,6 +961,18 @@ "@babel/helper-validator-identifier" "^7.25.7" to-fast-properties "^2.0.0" +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@jest/types@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" @@ -989,7 +1001,15 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== @@ -1007,6 +1027,129 @@ resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@rollup/plugin-babel@^6.0.4": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz#bd698e351fa9aa9619fcae780aea2a603d98e4c4" + integrity sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@rollup/pluginutils" "^5.0.1" + +"@rollup/plugin-json@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-6.1.0.tgz#fbe784e29682e9bb6dee28ea75a1a83702e7b805" + integrity sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA== + dependencies: + "@rollup/pluginutils" "^5.1.0" + +"@rollup/plugin-terser@^0.4.4": + version "0.4.4" + resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz#15dffdb3f73f121aa4fbb37e7ca6be9aeea91962" + integrity sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A== + dependencies: + serialize-javascript "^6.0.1" + smob "^1.0.0" + terser "^5.17.4" + +"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.2.tgz#d3bc9f0fea4fd4086aaac6aa102f3fa587ce8bd9" + integrity sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + +"@rollup/rollup-android-arm-eabi@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" + integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== + +"@rollup/rollup-android-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" + integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== + +"@rollup/rollup-darwin-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" + integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== + +"@rollup/rollup-darwin-x64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" + integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" + integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== + +"@rollup/rollup-linux-arm-musleabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" + integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== + +"@rollup/rollup-linux-arm64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" + integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== + +"@rollup/rollup-linux-arm64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" + integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" + integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== + +"@rollup/rollup-linux-riscv64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" + integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== + +"@rollup/rollup-linux-s390x-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" + integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== + +"@rollup/rollup-linux-x64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" + integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== + +"@rollup/rollup-linux-x64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" + integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== + +"@rollup/rollup-win32-arm64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" + integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== + +"@rollup/rollup-win32-ia32-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" + integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== + +"@rollup/rollup-win32-x64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" + integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== + +"@types/estree@1.0.6", "@types/estree@^1.0.0": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" @@ -1027,6 +1170,13 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/prettier@^1.0.0 || ^2.0.0 || ^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-3.0.0.tgz#e9bc8160230d3a461dab5c5b41cceef1ef723057" + integrity sha512-mFMBfMOz8QxhYVbuINtswBp9VL2b4Y0QqYHwqLz3YbgtfAcat2Dl6Y1o4e22S/OVE6Ebl9m7wWiMT2lSbAs1wA== + dependencies: + prettier "*" + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -1039,11 +1189,26 @@ dependencies: "@types/yargs-parser" "*" +acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + ansi-regex@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1051,13 +1216,18 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -1121,6 +1291,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -1138,6 +1315,11 @@ browserslist@^4.23.3, browserslist@^4.24.0: node-releases "^2.0.18" update-browserslist-db "^1.1.0" +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + caniuse-lite@^1.0.30001663: version "1.0.30001667" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" @@ -1199,6 +1381,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + commander@^6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" @@ -1221,6 +1408,15 @@ core-js-compat@^3.38.0, core-js-compat@^3.38.1: dependencies: browserslist "^4.23.3" +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" @@ -1228,11 +1424,31 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: dependencies: ms "^2.1.3" +diff@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + electron-to-chromium@^1.5.28: version "1.5.35" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -1243,6 +1459,11 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -1255,6 +1476,14 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -1287,6 +1516,18 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob@^10.3.7: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -1360,6 +1601,11 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -1372,6 +1618,20 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1397,6 +1657,26 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.hasin@4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.hasin/-/lodash.hasin-4.5.2.tgz#f91e352378d21ef7090b9e7687c2ca35c5b4d52a" + integrity sha512-AFAitwTSq1Ka/1J9uBaVxpLBP5OI3INQvkl4wKcgIYxoA0S3aqO1QWXHR9aCcOrWtPFqP7GzlFncZfe0Jz0kNw== + +lodash.isempty@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + integrity sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg== + +lodash.isnil@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" + integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== + +lodash.omitby@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791" + integrity sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ== + lodash@^4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -1409,6 +1689,11 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -1416,6 +1701,20 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +magic-string@0.30.5: + version "0.30.5" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" + integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + +magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -1431,6 +1730,18 @@ minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -1453,22 +1764,40 @@ once@^1.3.0: dependencies: wrappy "1" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + picocolors@^1.0.0, picocolors@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== -picomatch@^2.0.4, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -1478,6 +1807,11 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== +prettier@*: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + pretty-format@^24: version "24.9.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" @@ -1488,16 +1822,35 @@ pretty-format@^24: ansi-styles "^3.2.0" react-is "^16.8.4" +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: version "0.0.0-experimental-8d8e73f-20241009" resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== +react-dom@19.0.0-beta-26f2496093-20240514: + version "19.0.0-beta-26f2496093-20240514" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-26f2496093-20240514.tgz#5fe4e829db8d379303057f539900a61ed6ca2615" + integrity sha512-UvQ+K1l3DFQ34LDgfFSNuUGi9EC+yfE9tS6MdpNTd5fx7qC7KLfepfC/KpxWMQZ7JfE3axD4ZO6H4cBSpAZpqw== + dependencies: + scheduler "0.25.0-beta-26f2496093-20240514" + react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react@19.0.0-beta-26f2496093-20240514: + version "19.0.0-beta-26f2496093-20240514" + resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-beta-26f2496093-20240514.tgz#3a0d63746b3f9ebd461a0731191bd08047fb1dbb" + integrity sha512-ZsU/WjNZ6GfzMWsq2DcGjElpV9it8JmETHm9mAJuOJNhuJcWJxt8ltCJabONFRpDFq1A/DP0d0KFj9CTJVM4VA== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -1562,6 +1915,68 @@ resolve@^1.14.2: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +rimraf@5: + version "5.0.10" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" + integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== + dependencies: + glob "^10.3.7" + +rollup-plugin-banner2@^1.2.3: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-banner2/-/rollup-plugin-banner2-1.3.0.tgz#dbdabe5f6ef2616436120afdd3d8d000905b5e89" + integrity sha512-ehXBo4ziTayAwtyeNTc0Gc3IVBI6pqMtdvoX7B88WJHBXzA3BrUUvAQ7OSNOLB3ulgZyugDJypNh1PrFR3uiVQ== + dependencies: + magic-string "^0.25.7" + +rollup-plugin-prettier@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/rollup-plugin-prettier/-/rollup-plugin-prettier-4.1.1.tgz#eb74bd47c3cc3ba68bdf34b5323d0d7a47be8cec" + integrity sha512-ugpi/EqW12yJa4NO3o4f/wt/YHwiQovVGC2jxZgxuKO9osjt4lVxVA427+itl87XmQc6089ZkpDc6OpaOZKWgQ== + dependencies: + "@types/prettier" "^1.0.0 || ^2.0.0 || ^3.0.0" + diff "5.1.0" + lodash.hasin "4.5.2" + lodash.isempty "4.4.0" + lodash.isnil "4.0.0" + lodash.omitby "4.6.0" + magic-string "0.30.5" + +rollup@^4.22.4: + version "4.24.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" + integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.24.0" + "@rollup/rollup-android-arm64" "4.24.0" + "@rollup/rollup-darwin-arm64" "4.24.0" + "@rollup/rollup-darwin-x64" "4.24.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" + "@rollup/rollup-linux-arm-musleabihf" "4.24.0" + "@rollup/rollup-linux-arm64-gnu" "4.24.0" + "@rollup/rollup-linux-arm64-musl" "4.24.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" + "@rollup/rollup-linux-riscv64-gnu" "4.24.0" + "@rollup/rollup-linux-s390x-gnu" "4.24.0" + "@rollup/rollup-linux-x64-gnu" "4.24.0" + "@rollup/rollup-linux-x64-musl" "4.24.0" + "@rollup/rollup-win32-arm64-msvc" "4.24.0" + "@rollup/rollup-win32-ia32-msvc" "4.24.0" + "@rollup/rollup-win32-x64-msvc" "4.24.0" + fsevents "~2.3.2" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +scheduler@0.25.0-beta-26f2496093-20240514: + version "0.25.0-beta-26f2496093-20240514" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-26f2496093-20240514.tgz#a3bc0ff694ec6de7a78c1e48e1f8f4a8555bd77d" + integrity sha512-vDwOytLHFnA3SW2B1lNcbO+/qKVyLCX+KLpm+tRGNDsXpyxzRgkIaYGWmX+S70AJGchUHCtuqQ50GFeFgDbXUw== + semver@^5.6.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -1572,16 +1987,111 @@ semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +serialize-javascript@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +smob@^1.0.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" + integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +"string-width-cjs@npm:string-width@^4.2.0": + 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@^4.1.0: + 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" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm: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@^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" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -1601,6 +2111,16 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +terser@^5.17.4: + version "5.34.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.34.1.tgz#af40386bdbe54af0d063e0670afd55c3105abeb6" + integrity sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -1649,6 +2169,31 @@ update-browserslist-db@^1.1.0: escalade "^3.2.0" picocolors "^1.1.0" +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +"wrap-ansi-cjs@npm: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" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" From 0a1fdeee9ed6d93e2731ce7cc3957a75ce6a6da7 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 10 Oct 2024 11:39:54 -0400 Subject: [PATCH 262/426] [compiler] Consume compiled lib in react 18 app (#31166) `yarn dev` doesn't work quite correctly because of an outdated assumption in vite-plugin-react, I have a [PR open](https://github.com/vitejs/vite-plugin-react/pull/374) to address. However `yarn build` and `yarn preview` does work as expected. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31166). * #31167 * __->__ #31166 * #31165 --- .../runtime-compat/app-18/package.json | 5 +- .../runtime-compat/app-18/src/App.tsx | 31 +--- .../app-18/tsconfig.app.tsbuildinfo | 1 + .../app-18/tsconfig.node.tsbuildinfo | 1 + .../runtime-compat/app-18/vite.config.ts | 6 +- .../fixtures/runtime-compat/app-18/yarn.lock | 154 ++++++++++++++++-- 6 files changed, 160 insertions(+), 38 deletions(-) create mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo create mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo diff --git a/compiler/fixtures/runtime-compat/app-18/package.json b/compiler/fixtures/runtime-compat/app-18/package.json index c842bd49131bf..ef303670ad390 100644 --- a/compiler/fixtures/runtime-compat/app-18/package.json +++ b/compiler/fixtures/runtime-compat/app-18/package.json @@ -11,13 +11,16 @@ }, "dependencies": { "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-compiler-runtime": "0.0.0-experimental-8d8e73f-20241009", + "react-dom": "^18.3.1", + "runtime-compat-lib": "file:../lib" }, "devDependencies": { "@eslint/js": "^9.11.1", "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", + "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009", "eslint": "^9.11.1", "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", diff --git a/compiler/fixtures/runtime-compat/app-18/src/App.tsx b/compiler/fixtures/runtime-compat/app-18/src/App.tsx index 7bc88a7614856..e9833294f9195 100644 --- a/compiler/fixtures/runtime-compat/app-18/src/App.tsx +++ b/compiler/fixtures/runtime-compat/app-18/src/App.tsx @@ -1,33 +1,14 @@ -import {useState} from 'react'; -import reactLogo from './assets/react.svg'; -import viteLogo from '/vite.svg'; +import 'react'; import './App.css'; +// @ts-expect-error no types +import {useTime} from 'runtime-compat-lib'; function App() { - const [count, setCount] = useState(0); - + const time = useTime(); return ( <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

+

React 18

+ Current time: {time.toLocaleString()} ); } diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo b/compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000000000..fd34676dd9562 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo b/compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000000000..75ea0011dff53 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/vite.config.ts b/compiler/fixtures/runtime-compat/app-18/vite.config.ts index f4f509bd78512..dc514a333f215 100644 --- a/compiler/fixtures/runtime-compat/app-18/vite.config.ts +++ b/compiler/fixtures/runtime-compat/app-18/vite.config.ts @@ -3,5 +3,9 @@ import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [ + react({ + babel: {plugins: [['babel-plugin-react-compiler', {target: '18'}]]}, + }), + ], }); diff --git a/compiler/fixtures/runtime-compat/app-18/yarn.lock b/compiler/fixtures/runtime-compat/app-18/yarn.lock index 6023f48713b9f..59cf6935a7413 100644 --- a/compiler/fixtures/runtime-compat/app-18/yarn.lock +++ b/compiler/fixtures/runtime-compat/app-18/yarn.lock @@ -44,6 +44,17 @@ json5 "^2.2.3" semver "^6.3.1" +"@babel/generator@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" + integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== + dependencies: + "@babel/types" "^7.2.0" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/generator@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" @@ -172,7 +183,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": +"@babel/types@^7.0.0", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== @@ -377,6 +388,15 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -548,6 +568,26 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -573,6 +613,18 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^13.0.0": + version "13.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" + integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@8.8.1": version "8.8.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" @@ -685,7 +737,12 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-styles@^3.2.1: +ansi-regex@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -704,6 +761,19 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +babel-plugin-react-compiler@0.0.0-experimental-58c2b1c-20241009: + version "0.0.0-experimental-58c2b1c-20241009" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-58c2b1c-20241009.tgz#a840860c5da30cbc25db0671b9c715602539a175" + integrity sha512-/DSwpfz7c1hK5dpxxlLxQJtvXCF3RjN3ZCaJ43NM4BEvzTpaS0C0jasXVBEUIFumBcdaoirFbfZkyk9htY+6Xw== + dependencies: + "@babel/generator" "7.2.0" + "@babel/types" "^7.19.0" + chalk "4" + invariant "^2.2.4" + pretty-format "^24" + zod "^3.22.4" + zod-validation-error "^2.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -751,6 +821,14 @@ caniuse-lite@^1.0.30001663: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== +chalk@4, chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -760,14 +838,6 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1119,6 +1189,13 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1153,6 +1230,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + jsesc@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" @@ -1205,7 +1287,12 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -loose-envify@^1.1.0: +lodash@^4.17.10: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0, loose-envify@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -1333,6 +1420,16 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +pretty-format@^24: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -1343,6 +1440,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: + version "0.0.0-experimental-8d8e73f-20241009" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" + integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== + react-dom@^18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" @@ -1351,6 +1453,11 @@ react-dom@^18.3.1: loose-envify "^1.1.0" scheduler "^0.23.2" +react-is@^16.8.4: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-refresh@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" @@ -1405,6 +1512,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +"runtime-compat-lib@file:../lib": + version "0.0.0" + dependencies: + react-compiler-runtime "0.0.0-experimental-8d8e73f-20241009" + scheduler@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" @@ -1439,6 +1551,11 @@ source-map-js@^1.2.1: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -1475,6 +1592,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== + ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" @@ -1548,3 +1670,13 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod-validation-error@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-2.1.0.tgz#208eac75237dfed47c0018d2fe8fd03501bfc9ac" + integrity sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ== + +zod@^3.22.4: + version "3.23.8" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" + integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== From 77f438931f3da3bfe3dff91825737f06f2637f79 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 10 Oct 2024 11:40:06 -0400 Subject: [PATCH 263/426] [compiler] Consume compiled lib in react 19 app (#31167) it works --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31167). * __->__ #31167 * #31166 * #31165 --- .../runtime-compat/app-19/package.json | 4 +- .../runtime-compat/app-19/src/App.tsx | 31 +--- .../app-19/tsconfig.app.tsbuildinfo | 1 + .../app-19/tsconfig.node.tsbuildinfo | 1 + .../runtime-compat/app-19/vite.config.ts | 6 +- .../fixtures/runtime-compat/app-19/yarn.lock | 161 ++++++++++++++++-- 6 files changed, 166 insertions(+), 38 deletions(-) create mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo create mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo diff --git a/compiler/fixtures/runtime-compat/app-19/package.json b/compiler/fixtures/runtime-compat/app-19/package.json index d75d69a5569d0..3c1ba6859142d 100644 --- a/compiler/fixtures/runtime-compat/app-19/package.json +++ b/compiler/fixtures/runtime-compat/app-19/package.json @@ -11,13 +11,15 @@ }, "dependencies": { "react": "19.0.0-beta-26f2496093-20240514", - "react-dom": "19.0.0-beta-26f2496093-20240514" + "react-dom": "19.0.0-beta-26f2496093-20240514", + "runtime-compat-lib": "file:../lib" }, "devDependencies": { "@eslint/js": "^9.11.1", "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", + "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009", "eslint": "^9.11.1", "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", diff --git a/compiler/fixtures/runtime-compat/app-19/src/App.tsx b/compiler/fixtures/runtime-compat/app-19/src/App.tsx index 7bc88a7614856..35bafd4d2e681 100644 --- a/compiler/fixtures/runtime-compat/app-19/src/App.tsx +++ b/compiler/fixtures/runtime-compat/app-19/src/App.tsx @@ -1,33 +1,14 @@ -import {useState} from 'react'; -import reactLogo from './assets/react.svg'; -import viteLogo from '/vite.svg'; +import 'react'; import './App.css'; +// @ts-expect-error no types +import {useTime} from 'runtime-compat-lib'; function App() { - const [count, setCount] = useState(0); - + const time = useTime(); return ( <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

- Click on the Vite and React logos to learn more -

+

React 19

+ Current time: {time.toLocaleString()} ); } diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo b/compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000000000..fd34676dd9562 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo b/compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000000000..75ea0011dff53 --- /dev/null +++ b/compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/vite.config.ts b/compiler/fixtures/runtime-compat/app-19/vite.config.ts index f4f509bd78512..b0ffa6441cda1 100644 --- a/compiler/fixtures/runtime-compat/app-19/vite.config.ts +++ b/compiler/fixtures/runtime-compat/app-19/vite.config.ts @@ -3,5 +3,9 @@ import react from '@vitejs/plugin-react'; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [ + react({ + babel: {plugins: [['babel-plugin-react-compiler', {target: '19'}]]}, + }), + ], }); diff --git a/compiler/fixtures/runtime-compat/app-19/yarn.lock b/compiler/fixtures/runtime-compat/app-19/yarn.lock index 3e6ef0621a606..7d22e4cd3a7c8 100644 --- a/compiler/fixtures/runtime-compat/app-19/yarn.lock +++ b/compiler/fixtures/runtime-compat/app-19/yarn.lock @@ -44,6 +44,17 @@ json5 "^2.2.3" semver "^6.3.1" +"@babel/generator@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" + integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== + dependencies: + "@babel/types" "^7.2.0" + jsesc "^2.5.1" + lodash "^4.17.10" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/generator@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" @@ -172,7 +183,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": +"@babel/types@^7.0.0", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== @@ -377,6 +388,15 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -548,6 +568,26 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== + dependencies: + "@types/istanbul-lib-coverage" "*" + "@types/istanbul-lib-report" "*" + "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -573,6 +613,18 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^13.0.0": + version "13.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" + integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@8.8.1": version "8.8.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" @@ -685,7 +737,12 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-styles@^3.2.1: +ansi-regex@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -704,6 +761,19 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +babel-plugin-react-compiler@0.0.0-experimental-58c2b1c-20241009: + version "0.0.0-experimental-58c2b1c-20241009" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-58c2b1c-20241009.tgz#a840860c5da30cbc25db0671b9c715602539a175" + integrity sha512-/DSwpfz7c1hK5dpxxlLxQJtvXCF3RjN3ZCaJ43NM4BEvzTpaS0C0jasXVBEUIFumBcdaoirFbfZkyk9htY+6Xw== + dependencies: + "@babel/generator" "7.2.0" + "@babel/types" "^7.19.0" + chalk "4" + invariant "^2.2.4" + pretty-format "^24" + zod "^3.22.4" + zod-validation-error "^2.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -751,6 +821,14 @@ caniuse-lite@^1.0.30001663: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== +chalk@4, chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -760,14 +838,6 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1119,6 +1189,13 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1141,7 +1218,7 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0", 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== @@ -1153,6 +1230,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + jsesc@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" @@ -1205,6 +1287,18 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash@^4.17.10: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -1326,6 +1420,16 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +pretty-format@^24: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -1336,6 +1440,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: + version "0.0.0-experimental-8d8e73f-20241009" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" + integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== + react-dom@19.0.0-beta-26f2496093-20240514: version "19.0.0-beta-26f2496093-20240514" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-26f2496093-20240514.tgz#5fe4e829db8d379303057f539900a61ed6ca2615" @@ -1343,6 +1452,11 @@ react-dom@19.0.0-beta-26f2496093-20240514: dependencies: scheduler "0.25.0-beta-26f2496093-20240514" +react-is@^16.8.4: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + react-refresh@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" @@ -1395,6 +1509,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +"runtime-compat-lib@file:../lib": + version "0.0.0" + dependencies: + react-compiler-runtime "0.0.0-experimental-8d8e73f-20241009" + scheduler@0.25.0-beta-26f2496093-20240514: version "0.25.0-beta-26f2496093-20240514" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-26f2496093-20240514.tgz#a3bc0ff694ec6de7a78c1e48e1f8f4a8555bd77d" @@ -1427,6 +1546,11 @@ source-map-js@^1.2.1: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -1463,6 +1587,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== + ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" @@ -1536,3 +1665,13 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod-validation-error@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-2.1.0.tgz#208eac75237dfed47c0018d2fe8fd03501bfc9ac" + integrity sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ== + +zod@^3.22.4: + version "3.23.8" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" + integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== From fbfe37ee4010d36dad795d9144bb88fbeb8e1419 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Thu, 10 Oct 2024 12:23:44 -0400 Subject: [PATCH 264/426] [compiler] Test fixture: non-reactive phi creates 'dangling ref' scope (#31103) --- .../bug-invalid-phi-as-dependency.expect.md | 91 +++++++++++++++++++ .../bug-invalid-phi-as-dependency.tsx | 30 ++++++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 3 files changed, 122 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md new file mode 100644 index 0000000000000..32e2c9fd6483e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md @@ -0,0 +1,91 @@ + +## Input + +```javascript +import {CONST_TRUE, Stringify, mutate, useIdentity} from 'shared-runtime'; + +/** + * Fixture showing an edge case for ReactiveScope variable propagation. + * + * Found differences in evaluator results + * Non-forget (expected): + *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ * Forget: + *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ * [[ (exception in render) Error: invariant broken ]] + * + */ +function Component() { + const obj = CONST_TRUE ? {inner: {value: 'hello'}} : null; + const boxedInner = [obj?.inner]; + useIdentity(null); + mutate(obj); + if (boxedInner[0] !== obj?.inner) { + throw new Error('invariant broken'); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: 0}], + sequentialRenders: [{arg: 0}, {arg: 1}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { CONST_TRUE, Stringify, mutate, useIdentity } from "shared-runtime"; + +/** + * Fixture showing an edge case for ReactiveScope variable propagation. + * + * Found differences in evaluator results + * Non-forget (expected): + *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ * Forget: + *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ * [[ (exception in render) Error: invariant broken ]] + * + */ +function Component() { + const $ = _c(4); + const obj = CONST_TRUE ? { inner: { value: "hello" } } : null; + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = [obj?.inner]; + $[0] = t0; + } else { + t0 = $[0]; + } + const boxedInner = t0; + useIdentity(null); + mutate(obj); + if (boxedInner[0] !== obj?.inner) { + throw new Error("invariant broken"); + } + let t1; + if ($[1] !== obj || $[2] !== boxedInner) { + t1 = ; + $[1] = obj; + $[2] = boxedInner; + $[3] = t1; + } else { + t1 = $[3]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arg: 0 }], + sequentialRenders: [{ arg: 0 }, { arg: 1 }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.tsx new file mode 100644 index 0000000000000..a1a78bfa7e6b1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.tsx @@ -0,0 +1,30 @@ +import {CONST_TRUE, Stringify, mutate, useIdentity} from 'shared-runtime'; + +/** + * Fixture showing an edge case for ReactiveScope variable propagation. + * + * Found differences in evaluator results + * Non-forget (expected): + *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ * Forget: + *
{"obj":{"inner":{"value":"hello"},"wat0":"joe"},"inner":["[[ cyclic ref *2 ]]"]}
+ * [[ (exception in render) Error: invariant broken ]] + * + */ +function Component() { + const obj = CONST_TRUE ? {inner: {value: 'hello'}} : null; + const boxedInner = [obj?.inner]; + useIdentity(null); + mutate(obj); + if (boxedInner[0] !== obj?.inner) { + throw new Error('invariant broken'); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arg: 0}], + sequentialRenders: [{arg: 0}, {arg: 1}], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index dc90c9e29e2e7..351f242e40820 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -481,6 +481,7 @@ const skipFilter = new Set([ 'bug-invalid-hoisting-functionexpr', 'bug-try-catch-maybe-null-dependency', 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted', + 'bug-invalid-phi-as-dependency', 'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond', 'original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block', 'original-reactive-scopes-fork/bug-hoisted-declaration-with-scope', From 70fb1363912a35fc59c1bf648b963c3a0b719b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 10 Oct 2024 14:52:33 -0400 Subject: [PATCH 265/426] Fix limit without owner stacks (#31179) Move out of gate. --- packages/react-server/src/ReactFlightServer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 112070d718aa3..6adf619290e5e 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -3465,6 +3465,8 @@ function renderConsoleValue( if (element._owner != null) { outlineComponentInfo(request, element._owner); } + doNotLimit.add(element.props); + if (enableOwnerStacks) { let debugStack: null | ReactStackTrace = null; if (element._debugStack != null) { @@ -3475,7 +3477,6 @@ function renderConsoleValue( doNotLimit.add(debugStack[i]); } } - doNotLimit.add(element.props); return [ REACT_ELEMENT_TYPE, element.type, From 7b7fac073d1473df839a1caf8d0444c32bf4de49 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Thu, 10 Oct 2024 12:41:03 -0700 Subject: [PATCH 266/426] [compiler] Represent phis with places rather than identifiers Summary: The fact that phis are identifiers rather than places is unfortunate in a few cases. In some later analyses, we might wish to know whether a phi is reactive, but we don't have an easy way to do that currently. Most of the changes here is just replacing phi.id with phi.place.identifier and such. Interesting bits are EnterSSA (several functions now take places rather than identifiers, and InferReactivePlaces now needs to mark places as reactive explicitly. ghstack-source-id: 5f4fb396cd86b421008c37832a5735ac40f8806e Pull Request resolved: https://github.com/facebook/react/pull/31171 --- .../src/HIR/AssertConsistentIdentifiers.ts | 4 +- .../src/HIR/AssertValidMutableRanges.ts | 4 +- .../src/HIR/HIR.ts | 4 +- .../src/HIR/MergeConsecutiveBlocks.ts | 10 +-- .../src/HIR/PrintHIR.ts | 10 +-- .../src/HIR/PropagateScopeDependenciesHIR.ts | 2 +- .../src/Inference/InferAliasForPhis.ts | 4 +- .../src/Inference/InferMutableLifetimes.ts | 16 +++-- .../src/Inference/InferReactivePlaces.ts | 8 +-- .../src/Inference/InferReferenceEffects.ts | 4 +- .../src/Optimization/ConstantPropagation.ts | 4 +- .../src/Optimization/DeadCodeElimination.ts | 6 +- .../src/Optimization/PruneMaybeThrows.ts | 4 +- .../InferReactiveScopeVariables.ts | 15 +++-- .../src/SSA/EliminateRedundantPhi.ts | 15 ++--- .../src/SSA/EnterSSA.ts | 61 ++++++++++--------- .../src/TypeInference/InferTypes.ts | 6 +- .../src/TypeInference/PropagatePhiTypes.ts | 13 ++-- .../src/Validation/ValidateHooksUsage.ts | 7 ++- .../Validation/ValidateNoRefAccesInRender.ts | 5 +- 20 files changed, 103 insertions(+), 99 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts index dbe662c609a32..2588ee1f9a8da 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertConsistentIdentifiers.ts @@ -29,9 +29,9 @@ export function assertConsistentIdentifiers(fn: HIRFunction): void { const assignments: Set = new Set(); for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { - validate(identifiers, phi.id); + validate(identifiers, phi.place.identifier); for (const [, operand] of phi.operands) { - validate(identifiers, operand); + validate(identifiers, operand.identifier); } } for (const instr of block.instructions) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts index 95b11db40c90a..d44f6108eaa57 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/AssertValidMutableRanges.ts @@ -20,9 +20,9 @@ import { export function assertValidMutableRanges(fn: HIRFunction): void { for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { - visitIdentifier(phi.id); + visitIdentifier(phi.place.identifier); for (const [, operand] of phi.operands) { - visitIdentifier(operand); + visitIdentifier(operand.identifier); } } for (const instr of block.instructions) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 873082bdbeaa0..e771b386b3942 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -761,8 +761,8 @@ function _staticInvariantInstructionValueHasLocation( export type Phi = { kind: 'Phi'; - id: Identifier; - operands: Map; + place: Place; + operands: Map; }; /** diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts index 98721f636f8f9..ea132b772aa44 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/MergeConsecutiveBlocks.ts @@ -84,20 +84,14 @@ export function mergeConsecutiveBlocks(fn: HIRFunction): void { id: predecessor.terminal.id, lvalue: { kind: 'Identifier', - identifier: phi.id, + identifier: phi.place.identifier, effect: Effect.ConditionallyMutate, reactive: false, loc: GeneratedSource, }, value: { kind: 'LoadLocal', - place: { - kind: 'Identifier', - identifier: operand, - effect: Effect.Read, - reactive: false, - loc: GeneratedSource, - }, + place: {...operand}, loc: GeneratedSource, }, loc: GeneratedSource, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index c88d3bf773898..526ab7c7e52bb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -163,13 +163,13 @@ export function printInstruction(instr: ReactiveInstruction): string { export function printPhi(phi: Phi): string { const items = []; - items.push(printIdentifier(phi.id)); - items.push(printMutableRange(phi.id)); - items.push(printType(phi.id.type)); + items.push(printPlace(phi.place)); + items.push(printMutableRange(phi.place.identifier)); + items.push(printType(phi.place.identifier.type)); items.push(': phi('); const phis = []; - for (const [blockId, id] of phi.operands) { - phis.push(`bb${blockId}: ${printIdentifier(id)}`); + for (const [blockId, place] of phi.operands) { + phis.push(`bb${blockId}: ${printPlace(place)}`); } items.push(phis.join(', ')); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index ab2cf4cf56157..855ca9121d26b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -607,7 +607,7 @@ function collectDependencies( // Record referenced optional chains in phis for (const phi of block.phis) { for (const operand of phi.operands) { - const maybeOptionalChain = temporaries.get(operand[1].id); + const maybeOptionalChain = temporaries.get(operand[1].identifier.id); if (maybeOptionalChain) { context.visitDependency(maybeOptionalChain); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferAliasForPhis.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferAliasForPhis.ts index 126990196ccbd..e81e3ebdae7a2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferAliasForPhis.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferAliasForPhis.ts @@ -15,11 +15,11 @@ export function inferAliasForPhis( for (const [_, block] of func.body.blocks) { for (const phi of block.phis) { const isPhiMutatedAfterCreation: boolean = - phi.id.mutableRange.end > + phi.place.identifier.mutableRange.end > (block.instructions.at(0)?.id ?? block.terminal.id); if (isPhiMutatedAfterCreation) { for (const [, operand] of phi.operands) { - aliases.union([phi.id, operand]); + aliases.union([phi.place.identifier, operand.identifier]); } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts index 459baf4e287cc..508a970d931b0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutableLifetimes.ts @@ -116,19 +116,23 @@ export function inferMutableLifetimes( for (const [_, block] of func.body.blocks) { for (const phi of block.phis) { const isPhiMutatedAfterCreation: boolean = - phi.id.mutableRange.end > + phi.place.identifier.mutableRange.end > (block.instructions.at(0)?.id ?? block.terminal.id); if ( inferMutableRangeForStores && isPhiMutatedAfterCreation && - phi.id.mutableRange.start === 0 + phi.place.identifier.mutableRange.start === 0 ) { for (const [, operand] of phi.operands) { - if (phi.id.mutableRange.start === 0) { - phi.id.mutableRange.start = operand.mutableRange.start; + if (phi.place.identifier.mutableRange.start === 0) { + phi.place.identifier.mutableRange.start = + operand.identifier.mutableRange.start; } else { - phi.id.mutableRange.start = makeInstructionId( - Math.min(phi.id.mutableRange.start, operand.mutableRange.start), + phi.place.identifier.mutableRange.start = makeInstructionId( + Math.min( + phi.place.identifier.mutableRange.start, + operand.identifier.mutableRange.start, + ), ); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts index 20e1a97b08790..98b1ec75e1337 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts @@ -162,23 +162,23 @@ export function inferReactivePlaces(fn: HIRFunction): void { let hasReactiveControl = isReactiveControlledBlock(block.id); for (const phi of block.phis) { - if (reactiveIdentifiers.isReactiveIdentifier(phi.id)) { + if (reactiveIdentifiers.isReactive(phi.place)) { // Already marked reactive on a previous pass continue; } let isPhiReactive = false; for (const [, operand] of phi.operands) { - if (reactiveIdentifiers.isReactiveIdentifier(operand)) { + if (reactiveIdentifiers.isReactive(operand)) { isPhiReactive = true; break; } } if (isPhiReactive) { - reactiveIdentifiers.markReactiveIdentifier(phi.id); + reactiveIdentifiers.markReactive(phi.place); } else { for (const [pred] of phi.operands) { if (isReactiveControlledBlock(pred)) { - reactiveIdentifiers.markReactiveIdentifier(phi.id); + reactiveIdentifiers.markReactive(phi.place); break; } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts index 5231b7aef631c..8cf30a9666e25 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReferenceEffects.ts @@ -635,7 +635,7 @@ class InferenceState { inferPhi(phi: Phi): void { const values: Set = new Set(); for (const [_, operand] of phi.operands) { - const operandValues = this.#variables.get(operand.id); + const operandValues = this.#variables.get(operand.identifier.id); // This is a backedge that will be handled later by State.merge if (operandValues === undefined) continue; for (const v of operandValues) { @@ -644,7 +644,7 @@ class InferenceState { } if (values.size > 0) { - this.#variables.set(phi.id.id, values); + this.#variables.set(phi.place.identifier.id, values); } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts index 112cca7491483..24498012a08eb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts @@ -117,7 +117,7 @@ function applyConstantPropagation( for (const phi of block.phis) { let value = evaluatePhi(phi, constants); if (value !== null) { - constants.set(phi.id.id, value); + constants.set(phi.place.identifier.id, value); } } @@ -167,7 +167,7 @@ function applyConstantPropagation( function evaluatePhi(phi: Phi, constants: Constants): Constant | null { let value: Constant | null = null; for (const [, operand] of phi.operands) { - const operandValue = constants.get(operand.id) ?? null; + const operandValue = constants.get(operand.identifier.id) ?? null; // did not find a constant, can't constant propogate if (operandValue === null) { return null; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts index 3cdba101a82ac..885ec2b3ab2eb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts @@ -42,7 +42,7 @@ export function deadCodeElimination(fn: HIRFunction): void { */ for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { - if (!state.isIdOrNameUsed(phi.id)) { + if (!state.isIdOrNameUsed(phi.place.identifier)) { block.phis.delete(phi); } } @@ -159,9 +159,9 @@ function findReferencedIdentifiers(fn: HIRFunction): State { } } for (const phi of block.phis) { - if (state.isIdOrNameUsed(phi.id)) { + if (state.isIdOrNameUsed(phi.place.identifier)) { for (const [_pred, operand] of phi.operands) { - state.reference(operand); + state.reference(operand.identifier); } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts index 3843cdf23fc2d..9175fbdd1af1b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/PruneMaybeThrows.ts @@ -23,7 +23,7 @@ import { removeUnnecessaryTryCatch, removeUnreachableForUpdates, } from '../HIR/HIRBuilder'; -import {printIdentifier} from '../HIR/PrintHIR'; +import {printPlace} from '../HIR/PrintHIR'; /* * This pass prunes `maybe-throw` terminals for blocks that can provably *never* throw. @@ -55,7 +55,7 @@ export function pruneMaybeThrows(fn: HIRFunction): void { loc: GeneratedSource, description: `Could not find mapping for predecessor bb${predecessor} in block bb${ block.id - } for phi ${printIdentifier(phi.id)}`, + } for phi ${printPlace(phi.place)}`, suggestions: null, }); phi.operands.delete(predecessor); diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts index 0d0b37ce58afe..098139b150d5a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/InferReactiveScopeVariables.ts @@ -281,22 +281,25 @@ export function findDisjointMutableValues( */ for (const phi of block.phis) { if ( - phi.id.mutableRange.start + 1 !== phi.id.mutableRange.end && - phi.id.mutableRange.end > + phi.place.identifier.mutableRange.start + 1 !== + phi.place.identifier.mutableRange.end && + phi.place.identifier.mutableRange.end > (block.instructions.at(0)?.id ?? block.terminal.id) ) { - const operands = [phi.id]; - const declaration = declarations.get(phi.id.declarationId); + const operands = [phi.place.identifier]; + const declaration = declarations.get( + phi.place.identifier.declarationId, + ); if (declaration !== undefined) { operands.push(declaration); } for (const [_, phiId] of phi.operands) { - operands.push(phiId); + operands.push(phiId.identifier); } scopeIdentifiers.union(operands); } else if (fn.env.config.enableForest) { for (const [, phiId] of phi.operands) { - scopeIdentifiers.union([phi.id, phiId]); + scopeIdentifiers.union([phi.place.identifier, phiId.identifier]); } } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts index b5b0afb41236a..bae038f9bd9df 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/EliminateRedundantPhi.ts @@ -68,18 +68,13 @@ export function eliminateRedundantPhi( // Find any redundant phis phis: for (const phi of block.phis) { // Remap phis in case operands are from eliminated phis - phi.operands = new Map( - Array.from(phi.operands).map(([block, id]) => [ - block, - rewrites.get(id) ?? id, - ]), - ); + phi.operands.forEach((place, _) => rewritePlace(place, rewrites)); // Find if the phi can be eliminated let same: Identifier | null = null; for (const [_, operand] of phi.operands) { if ( - (same !== null && operand.id === same.id) || - operand.id === phi.id.id + (same !== null && operand.identifier.id === same.id) || + operand.identifier.id === phi.place.identifier.id ) { /* * This operand is the same as the phi or is the same as the @@ -94,7 +89,7 @@ export function eliminateRedundantPhi( continue phis; } else { // First non-phi operand - same = operand; + same = operand.identifier; } } CompilerError.invariant(same !== null, { @@ -103,7 +98,7 @@ export function eliminateRedundantPhi( loc: null, suggestions: null, }); - rewrites.set(phi.id, same); + rewrites.set(phi.place.identifier, same); block.phis.delete(phi); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts b/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts index 73942769c22be..caba0d3c36992 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/SSA/EnterSSA.ts @@ -18,7 +18,7 @@ import { Phi, Place, } from '../HIR/HIR'; -import {printIdentifier} from '../HIR/PrintHIR'; +import {printIdentifier, printPlace} from '../HIR/PrintHIR'; import { eachTerminalSuccessor, mapInstructionLValues, @@ -27,8 +27,8 @@ import { } from '../HIR/visitors'; type IncompletePhi = { - oldId: Identifier; - newId: Identifier; + oldPlace: Place; + newPlace: Place; }; type State = { @@ -122,33 +122,33 @@ class SSABuilder { } getPlace(oldPlace: Place): Place { - const newId = this.getIdAt(oldPlace.identifier, this.#current!.id); + const newId = this.getIdAt(oldPlace, this.#current!.id); return { ...oldPlace, identifier: newId, }; } - getIdAt(oldId: Identifier, blockId: BlockId): Identifier { + getIdAt(oldPlace: Place, blockId: BlockId): Identifier { // check if Place is defined locally const block = this.#blocks.get(blockId)!; const state = this.#states.get(block)!; - if (state.defs.has(oldId)) { - return state.defs.get(oldId)!; + if (state.defs.has(oldPlace.identifier)) { + return state.defs.get(oldPlace.identifier)!; } if (block.preds.size == 0) { /* * We're at the entry block and haven't found our defintion yet. * console.log( - * `Unable to find "${printIdentifier( - * oldId + * `Unable to find "${printPlace( + * oldPlace * )}" in bb${blockId}, assuming it's a global` * ); */ - this.#unknown.add(oldId); - return oldId; + this.#unknown.add(oldPlace.identifier); + return oldPlace.identifier; } if (this.unsealedPreds.get(block)! > 0) { @@ -156,52 +156,55 @@ class SSABuilder { * We haven't visited all our predecessors, let's place an incomplete phi * for now. */ - const newId = this.makeId(oldId); - state.incompletePhis.push({oldId, newId}); - state.defs.set(oldId, newId); + const newId = this.makeId(oldPlace.identifier); + state.incompletePhis.push({ + oldPlace, + newPlace: {...oldPlace, identifier: newId}, + }); + state.defs.set(oldPlace.identifier, newId); return newId; } // Only one predecessor, let's check there if (block.preds.size == 1) { const [pred] = block.preds; - const newId = this.getIdAt(oldId, pred); - state.defs.set(oldId, newId); + const newId = this.getIdAt(oldPlace, pred); + state.defs.set(oldPlace.identifier, newId); return newId; } // There are multiple predecessors, we may need a phi. - const newId = this.makeId(oldId); + const newId = this.makeId(oldPlace.identifier); /* * Adding a phi may loop back to our block if there is a loop in the CFG. We * update our defs before adding the phi to terminate the recursion rather than * looping infinitely. */ - state.defs.set(oldId, newId); - return this.addPhi(block, oldId, newId); + state.defs.set(oldPlace.identifier, newId); + return this.addPhi(block, oldPlace, {...oldPlace, identifier: newId}); } - addPhi(block: BasicBlock, oldId: Identifier, newId: Identifier): Identifier { - const predDefs: Map = new Map(); + addPhi(block: BasicBlock, oldPlace: Place, newPlace: Place): Identifier { + const predDefs: Map = new Map(); for (const predBlockId of block.preds) { - const predId = this.getIdAt(oldId, predBlockId); - predDefs.set(predBlockId, predId); + const predId = this.getIdAt(oldPlace, predBlockId); + predDefs.set(predBlockId, {...oldPlace, identifier: predId}); } const phi: Phi = { kind: 'Phi', - id: newId, + place: newPlace, operands: predDefs, }; block.phis.add(phi); - return newId; + return newPlace.identifier; } fixIncompletePhis(block: BasicBlock): void { const state = this.#states.get(block)!; for (const phi of state.incompletePhis) { - this.addPhi(block, phi.oldId, phi.newId); + this.addPhi(block, phi.oldPlace, phi.newPlace); } } @@ -223,9 +226,9 @@ class SSABuilder { for (const incompletePhi of state.incompletePhis) { text.push( - ` iphi \$${printIdentifier( - incompletePhi.newId, - )} = \$${printIdentifier(incompletePhi.oldId)}`, + ` iphi \$${printPlace( + incompletePhi.newPlace, + )} = \$${printPlace(incompletePhi.oldPlace)}`, ); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index 25bc87838ae83..0270723c3e863 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -69,7 +69,7 @@ export function inferTypes(func: HIRFunction): void { function apply(func: HIRFunction, unifier: Unifier): void { for (const [_, block] of func.body.blocks) { for (const phi of block.phis) { - phi.id.type = unifier.get(phi.id.type); + phi.place.identifier.type = unifier.get(phi.place.identifier.type); } for (const instr of block.instructions) { for (const operand of eachInstructionLValue(instr)) { @@ -127,9 +127,9 @@ function* generate( const returnTypes: Array = []; for (const [_, block] of func.body.blocks) { for (const phi of block.phis) { - yield equation(phi.id.type, { + yield equation(phi.place.identifier.type, { kind: 'Phi', - operands: [...phi.operands.values()].map(id => id.type), + operands: [...phi.operands.values()].map(id => id.identifier.type), }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/PropagatePhiTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/PropagatePhiTypes.ts index b33c8773dc0c7..0369945525bcf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/PropagatePhiTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/PropagatePhiTypes.ts @@ -62,21 +62,24 @@ export function propagatePhiTypes(fn: HIRFunction): void { * We also don't propagate scopes for named variables, to preserve compatibility * with previous LeaveSSA behavior. */ - if (phi.id.type.kind !== 'Type' || phi.id.name !== null) { + if ( + phi.place.identifier.type.kind !== 'Type' || + phi.place.identifier.name !== null + ) { continue; } let type: Type | null = null; for (const [, operand] of phi.operands) { if (type === null) { - type = operand.type; - } else if (!typeEquals(type, operand.type)) { + type = operand.identifier.type; + } else if (!typeEquals(type, operand.identifier.type)) { type = null; break; } } if (type !== null) { - phi.id.type = type; - propagated.add(phi.id.id); + phi.place.identifier.type = type; + propagated.add(phi.place.identifier.id); } } for (const instr of block.instructions) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts index 74f6346b3a37b..53640da5020bd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateHooksUsage.ts @@ -198,11 +198,12 @@ export function validateHooksUsage(fn: HIRFunction): void { for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { let kind: Kind = - phi.id.name !== null && isHookName(phi.id.name.value) + phi.place.identifier.name !== null && + isHookName(phi.place.identifier.name.value) ? Kind.PotentialHook : Kind.Local; for (const [, operand] of phi.operands) { - const operandKind = valueKinds.get(operand.id); + const operandKind = valueKinds.get(operand.identifier.id); /* * NOTE: we currently skip operands whose value is unknown * (which can only occur for functions with loops), we may @@ -213,7 +214,7 @@ export function validateHooksUsage(fn: HIRFunction): void { kind = joinKinds(kind, operandKind); } } - valueKinds.set(phi.id.id, kind); + valueKinds.set(phi.place.identifier.id, kind); } for (const instr of block.instructions) { switch (instr.value.kind) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index 5f98b0ee8e4af..7fb835e0496c6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -209,10 +209,11 @@ function validateNoRefAccessInRenderImpl( for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { env.set( - phi.id.id, + phi.place.identifier.id, joinRefAccessTypes( ...Array(...phi.operands.values()).map( - operand => env.get(operand.id) ?? ({kind: 'None'} as const), + operand => + env.get(operand.identifier.id) ?? ({kind: 'None'} as const), ), ), ); From 5636fad840942cfea80301d91e931a50c6370d19 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Thu, 10 Oct 2024 18:12:47 -0400 Subject: [PATCH 267/426] [string-refs] log string ref from prod (#31161) If passed as a feature flag, this calls the configured function when a string ref is used even from prod code to find the last usages. --- packages/react/src/jsx/ReactJSXElement.js | 28 ++++++++++------- packages/shared/ReactFeatureFlags.js | 7 +++++ .../forks/ReactFeatureFlags.native-fb.js | 1 + .../forks/ReactFeatureFlags.native-oss.js | 1 + .../forks/ReactFeatureFlags.test-renderer.js | 1 + .../ReactFeatureFlags.test-renderer.www.js | 1 + .../forks/ReactFeatureFlags.www-dynamic.js | 1 + .../shared/forks/ReactFeatureFlags.www.js | 5 ++-- scripts/flags/flags.js | 30 ++++++++++++++----- 9 files changed, 55 insertions(+), 20 deletions(-) diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index a0de9c8e145c8..893806def2c47 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -24,6 +24,7 @@ import { disableStringRefs, disableDefaultPropsExceptForClasses, enableOwnerStacks, + enableLogStringRefsProd, } from 'shared/ReactFeatureFlags'; import {checkPropStringCoercion} from 'shared/CheckStringCoercion'; import {ClassComponent} from 'react-reconciler/src/ReactWorkTags'; @@ -76,7 +77,7 @@ let didWarnAboutStringRefs; let didWarnAboutElementRef; let didWarnAboutOldJSXRuntime; -if (__DEV__) { +if (__DEV__ || enableLogStringRefsProd) { didWarnAboutStringRefs = {}; didWarnAboutElementRef = {}; } @@ -1314,22 +1315,27 @@ function stringRefAsCallbackRef(stringRef, type, owner, value) { ); } - if (__DEV__) { + if (__DEV__ || enableLogStringRefsProd) { if ( // Will already warn with "Function components cannot be given refs" !(typeof type === 'function' && !isReactClass(type)) ) { const componentName = getComponentNameFromFiber(owner) || 'Component'; if (!didWarnAboutStringRefs[componentName]) { - console.error( - 'Component "%s" contains the string ref "%s". Support for string refs ' + - 'will be removed in a future major release. We recommend using ' + - 'useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref', - componentName, - stringRef, - ); + if (enableLogStringRefsProd) { + enableLogStringRefsProd(componentName, stringRef); + } + if (__DEV__) { + console.error( + 'Component "%s" contains the string ref "%s". Support for string refs ' + + 'will be removed in a future major release. We recommend using ' + + 'useRef() or createRef() instead. ' + + 'Learn more about using refs safely here: ' + + 'https://react.dev/link/strict-mode-string-ref', + componentName, + stringRef, + ); + } didWarnAboutStringRefs[componentName] = true; } } diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 058e2be089b0f..5a11217452e57 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -215,6 +215,13 @@ export const disableClientCache = true; // during element creation. export const enableRefAsProp = true; export const disableStringRefs = true; +/** + * If set to a function, the function will be called with the component name + * and ref string. + * + * NOTE: This happens also in the production build. + */ +export const enableLogStringRefsProd: null | ((string, string) => void) = null; // Warn on any usage of ReactTestRenderer export const enableReactTestRendererWarning = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index bac5977f5e1b4..de6ee64caad20 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -65,6 +65,7 @@ export const enableLazyContextPropagation = true; export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; +export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableNoCloningMemoCache = false; export const enableOwnerStacks = false; export const enablePostpone = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index d5f0d3bb9ca88..7b5e29a8fcc33 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -56,6 +56,7 @@ export const enableContextProfiling = false; export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; +export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableNoCloningMemoCache = false; export const enableObjectFiber = false; export const enableOwnerStacks = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 746778b7b2c27..2fe7b8a19a9d5 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -44,6 +44,7 @@ export const enableUseEffectEventHook = false; export const favorSafetyOverHydrationPerf = true; export const enableComponentStackLocations = true; export const enableLegacyFBSupport = false; +export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableFilterEmptyStringAttributesDOM = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableFabricCompleteRootInCommitPhase = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 1fa1b40280ff3..7d9c3818c8f1b 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -46,6 +46,7 @@ export const enableUseEffectEventHook = false; export const favorSafetyOverHydrationPerf = true; export const enableComponentStackLocations = true; export const enableLegacyFBSupport = false; +export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableFilterEmptyStringAttributesDOM = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableRenderableContext = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 8a82b7f55241b..3888339bff2ed 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -21,6 +21,7 @@ export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__; export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__; +export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableNoCloningMemoCache = __VARIANT__; export const enableObjectFiber = __VARIANT__; export const enableRenderableContext = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 95a5a4c55cacd..7484832a68b40 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -22,20 +22,21 @@ export const { enableDebugTracing, enableDeferRootSchedulingToMicrotask, enableDO_NOT_USE_disableStrictPassiveEffect, + enableHiddenSubtreeInsertionEffectCleanup, enableInfiniteRenderLoopDetection, + enableLogStringRefsProd, enableNoCloningMemoCache, enableObjectFiber, enableRenderableContext, enableRetryLaneExpiration, + enableSiblingPrerendering, enableTransitionTracing, enableTrustedTypesIntegration, - enableHiddenSubtreeInsertionEffectCleanup, favorSafetyOverHydrationPerf, renameElementSymbol, retryLaneExpirationMs, syncLaneExpirationMs, transitionLaneExpirationMs, - enableSiblingPrerendering, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build. diff --git a/scripts/flags/flags.js b/scripts/flags/flags.js index 50d263cd498ef..a578304199a2c 100644 --- a/scripts/flags/flags.js +++ b/scripts/flags/flags.js @@ -172,7 +172,7 @@ function getNextMajorFlagValue(flag) { const value = ReactFeatureFlagsMajor[flag]; if (value === true || value === 'next') { return '✅'; - } else if (value === false || value === 'experimental') { + } else if (value === false || value === null || value === 'experimental') { return '❌'; } else if (value === 'profile') { return '📊'; @@ -189,7 +189,12 @@ function getOSSCanaryFlagValue(flag) { const value = ReactFeatureFlags[flag]; if (value === true) { return '✅'; - } else if (value === false || value === 'experimental' || value === 'next') { + } else if ( + value === false || + value === null || + value === 'experimental' || + value === 'next' + ) { return '❌'; } else if (value === 'profile') { return '📊'; @@ -206,7 +211,7 @@ function getOSSExperimentalFlagValue(flag) { const value = ReactFeatureFlags[flag]; if (value === true || value === 'experimental') { return '✅'; - } else if (value === false || value === 'next') { + } else if (value === false || value === null || value === 'next') { return '❌'; } else if (value === 'profile') { return '📊'; @@ -225,7 +230,7 @@ function getWWWModernFlagValue(flag) { const value = ReactFeatureFlagsWWW[flag]; if (value === true || value === 'experimental') { return '✅'; - } else if (value === false || value === 'next') { + } else if (value === false || value === null || value === 'next') { return '❌'; } else if (value === 'profile') { return '📊'; @@ -244,7 +249,12 @@ function getWWWClassicFlagValue(flag) { const value = ReactFeatureFlagsWWW[flag]; if (value === true) { return '✅'; - } else if (value === false || value === 'experimental' || value === 'next') { + } else if ( + value === false || + value === null || + value === 'experimental' || + value === 'next' + ) { return '❌'; } else if (value === 'profile') { return '📊'; @@ -265,7 +275,7 @@ function getRNNextMajorFlagValue(flag) { return '✅'; } else if (value === 'next-todo') { return '📋'; - } else if (value === false || value === 'experimental') { + } else if (value === false || value === null || value === 'experimental') { return '❌'; } else if (value === 'profile') { return '📊'; @@ -286,6 +296,7 @@ function getRNOSSFlagValue(flag) { return '✅'; } else if ( value === false || + value === null || value === 'experimental' || value === 'next' || value === 'next-todo' @@ -308,7 +319,12 @@ function getRNFBFlagValue(flag) { const value = ReactFeatureFlagsNativeFB[flag]; if (value === true) { return '✅'; - } else if (value === false || value === 'experimental' || value === 'next') { + } else if ( + value === false || + value === null || + value === 'experimental' || + value === 'next' + ) { return '❌'; } else if (value === 'profile') { return '📊'; From 09111202d617477b63507b41e8b6c3101b4afd87 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Fri, 11 Oct 2024 14:51:59 +0200 Subject: [PATCH 268/426] eslint-plugin-react-hooks: Release 5.0.0 (#31176) Co-authored-by: lauren --- packages/eslint-plugin-react-hooks/CHANGELOG.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin-react-hooks/CHANGELOG.md b/packages/eslint-plugin-react-hooks/CHANGELOG.md index 589574ede95cb..f894ecc136696 100644 --- a/packages/eslint-plugin-react-hooks/CHANGELOG.md +++ b/packages/eslint-plugin-react-hooks/CHANGELOG.md @@ -1,7 +1,21 @@ -## 5.0.0 (next release) +## 5.0.0 * **New Violations:** Component names now need to start with an uppercase letter instead of a non-lowercase letter. This means `_Button` or `_component` are no longer valid. ([@kassens](https://github.com/kassens)) in [#25162](https://github.com/facebook/react/pull/25162) +- Consider dispatch from `useActionState` stable. ([@eps1lon](https://github.com/eps1lon) in [#29665](https://github.com/facebook/react/pull/29665)) +- Add support for ESLint v9. ([@eps1lon](https://github.com/eps1lon) in [#28773](https://github.com/facebook/react/pull/28773)) +- Accept `as` expression in callback. ([@StyleShit](https://github.com/StyleShit) in [#28202](https://github.com/facebook/react/pull/28202)) +- Accept `as` expressions in deps array. ([@StyleShit](https://github.com/StyleShit) in [#28189](https://github.com/facebook/react/pull/28189)) +- Treat `React.use()` the same as `use()`. ([@kassens](https://github.com/kassens) in [#27769](https://github.com/facebook/react/pull/27769)) +- Move `use()` lint to non-experimental. ([@kassens](https://github.com/kassens) in [#27768](https://github.com/facebook/react/pull/27768)) +- Support Flow `as` expressions. ([@cpojer](https://github.com/cpojer) in [#27590](https://github.com/facebook/react/pull/27590)) +- Allow `useEffect(fn, undefined)`. ([@kassens](https://github.com/kassens) in [#27525](https://github.com/facebook/react/pull/27525)) +- Disallow hooks in async functions. ([@acdlite](https://github.com/acdlite) in [#27045](https://github.com/facebook/react/pull/27045)) +- Rename experimental `useEvent` to `useEffectEvent`. ([@sebmarkbage](https://github.com/sebmarkbage) in [#25881](https://github.com/facebook/react/pull/25881)) +- Lint for presence of `useEvent` functions in dependency lists. ([@poteto](https://github.com/poteto) in [#25512](https://github.com/facebook/react/pull/25512)) +- Check `useEvent` references instead. ([@poteto](https://github.com/poteto) in [#25319](https://github.com/facebook/react/pull/25319)) +- Update `RulesOfHooks` with `useEvent` rules. ([@poteto](https://github.com/poteto) in [#25285](https://github.com/facebook/react/pull/25285)) + ## 4.6.0 ## 4.5.0 From 2011074ab8fc6182a2ad0af2766409c1e15f7fc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:29:18 -0400 Subject: [PATCH 269/426] Bump json5 from 2.2.1 to 2.2.3 in /compiler (#31185) Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
Release notes

Sourced from json5's releases.

v2.2.3

  • Fix: json5@2.2.3 is now the 'latest' release according to npm instead of v1.0.2. (#299)

v2.2.2

  • Fix: Properties with the name __proto__ are added to objects and arrays. (#199) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! (#295).
Changelog

Sourced from json5's changelog.

v2.2.3 [code, diff]

  • Fix: json5@2.2.3 is now the 'latest' release according to npm instead of v1.0.2. (#299)

v2.2.2 [code, diff]

  • Fix: Properties with the name __proto__ are added to objects and arrays. (#199) This also fixes a prototype pollution vulnerability reported by Jonathan Gregson! (#295).
Commits
  • c3a7524 2.2.3
  • 94fd06d docs: update CHANGELOG for v2.2.3
  • 3b8cebf docs(security): use GitHub security advisories
  • f0fd9e1 docs: publish a security policy
  • 6a91a05 docs(template): bug -> bug report
  • 14f8cb1 2.2.2
  • 10cc7ca docs: update CHANGELOG for v2.2.2
  • 7774c10 fix: add proto to objects and arrays
  • edde30a Readme: slight tweak to intro
  • 97286f8 Improve example in readme
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=json5&package-manager=npm_and_yarn&previous-version=2.2.1&new-version=2.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- compiler/yarn.lock | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/yarn.lock b/compiler/yarn.lock index 8f4f318e7f826..d29f7367977a7 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -6186,12 +6186,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json5@^2.1.0, json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== - -json5@^2.2.3: +json5@^2.1.0, json5@^2.2.1, 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== From 9c525ea44aef36b614c8dac2f351ebec0917606c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:29:34 -0400 Subject: [PATCH 270/426] Bump micromatch from 4.0.5 to 4.0.8 in /compiler (#31186) Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8.
Release notes

Sourced from micromatch's releases.

4.0.8

Ultimate release that fixes both CVE-2024-4067 and CVE-2024-4068. We consider the issues low-priority, so even if you see automated scanners saying otherwise, don't be scared.

Changelog

Sourced from micromatch's changelog.

[4.0.8] - 2024-08-22

  • backported CVE-2024-4067 fix (from v4.0.6) over to 4.x branch

[4.0.7] - 2024-05-22

  • this is basically v4.0.5, with some README updates
  • it is vulnerable to CVE-2024-4067
  • Updated braces to v3.0.3 to avoid CVE-2024-4068
  • does NOT break API compatibility

[4.0.6] - 2024-05-21

  • Added hasBraces to check if a pattern contains braces.
  • Fixes CVE-2024-4067
  • BREAKS API COMPATIBILITY
  • Should be labeled as a major release, but it's not.
Commits
  • 8bd704e 4.0.8
  • a0e6841 run verb to generate README documentation
  • 4ec2884 Merge branch 'v4' into hauserkristof-feature/v4.0.8
  • 03aa805 Merge pull request #266 from hauserkristof/feature/v4.0.8
  • 814f5f7 lint
  • 67fcce6 fix: CHANGELOG about braces & CVE-2024-4068, v4.0.5
  • 113f2e3 fix: CVE numbers in CHANGELOG
  • d9dbd9a feat: updated CHANGELOG
  • 2ab1315 fix: use actions/setup-node@v4
  • 1406ea3 feat: rework test to work on macos with node 10,12 and 14
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=micromatch&package-manager=npm_and_yarn&previous-version=4.0.5&new-version=4.0.8)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- compiler/yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/yarn.lock b/compiler/yarn.lock index d29f7367977a7..8239089c72992 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -3527,12 +3527,12 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browser-process-hrtime@^1.0.0: version "1.0.0" @@ -4380,10 +4380,10 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -6399,11 +6399,11 @@ merge2@^1.3.0, merge2@^1.4.1: integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: From 6cf5bd90135823d249fb5270896f238d04ec296c Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 11 Oct 2024 16:14:32 -0700 Subject: [PATCH 271/426] [compiler] Allow refs to be lazily initialized during render Summary: The official guidance for useRef notes an exception to the rule that refs cannot be accessed during render: to avoid recreating the ref's contents, you can test that the ref is uninitialized and then initialize it using an if statement: ``` if (ref.current == null) { ref.current = SomeExpensiveOperation() } ``` The compiler didn't recognize this exception, however, leading to code that obeyed all the official guidance for refs being rejected by the compiler. This PR fixes that, by extending the ref validation machinery with an awareness of guard operations that allow lazy initialization. We now understand `== null` and similar operations, when applied to a ref and consumed by an if terminal, as marking the consequent of the if as a block in which the ref can be safely written to. In order to do so we need to create a notion of ref ids, which link different usages of the same ref via both the ref and the ref value. ghstack-source-id: d2729274f351e1eb0268f28f629fa4c2568ebc4d Pull Request resolved: https://github.com/facebook/react/pull/31188 --- .../Validation/ValidateNoRefAccesInRender.ts | 188 +++++++++++++++--- .../allow-ref-initialization.expect.md | 42 ++++ .../compiler/allow-ref-initialization.js | 14 ++ ...ror.ref-initialization-arbitrary.expect.md | 39 ++++ .../error.ref-initialization-arbitrary.js | 16 ++ .../error.ref-initialization-call-2.expect.md | 35 ++++ .../error.ref-initialization-call-2.js | 14 ++ .../error.ref-initialization-call.expect.md | 35 ++++ .../compiler/error.ref-initialization-call.js | 14 ++ .../error.ref-initialization-linear.expect.md | 36 ++++ .../error.ref-initialization-linear.js | 15 ++ .../error.ref-initialization-nonif.expect.md | 38 ++++ .../error.ref-initialization-nonif.js | 15 ++ .../error.ref-initialization-other.expect.md | 36 ++++ .../error.ref-initialization-other.js | 15 ++ ...ref-initialization-post-access-2.expect.md | 36 ++++ .../error.ref-initialization-post-access-2.js | 15 ++ ...r.ref-initialization-post-access.expect.md | 36 ++++ .../error.ref-initialization-post-access.js | 15 ++ 19 files changed, 628 insertions(+), 26 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index 7fb835e0496c6..efc8211f937b7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -7,8 +7,8 @@ import {CompilerError, ErrorSeverity} from '../CompilerError'; import { + BlockId, HIRFunction, - Identifier, IdentifierId, Place, SourceLocation, @@ -17,6 +17,7 @@ import { isUseRefType, } from '../HIR'; import { + eachInstructionOperand, eachInstructionValueOperand, eachPatternOperand, eachTerminalOperand, @@ -44,11 +45,32 @@ import {Err, Ok, Result} from '../Utils/Result'; * or based on property name alone (`foo.current` might be a ref). */ -type RefAccessType = {kind: 'None'} | RefAccessRefType; +const opaqueRefId = Symbol(); +type RefId = number & {[opaqueRefId]: 'RefId'}; + +function makeRefId(id: number): RefId { + CompilerError.invariant(id >= 0 && Number.isInteger(id), { + reason: 'Expected identifier id to be a non-negative integer', + description: null, + loc: null, + suggestions: null, + }); + return id as RefId; +} +let _refId = 0; +function nextRefId(): RefId { + return makeRefId(_refId++); +} + +type RefAccessType = + | {kind: 'None'} + | {kind: 'Nullable'} + | {kind: 'Guard'; refId: RefId} + | RefAccessRefType; type RefAccessRefType = - | {kind: 'Ref'} - | {kind: 'RefValue'; loc?: SourceLocation} + | {kind: 'Ref'; refId: RefId} + | {kind: 'RefValue'; loc?: SourceLocation; refId?: RefId} | {kind: 'Structure'; value: null | RefAccessRefType; fn: null | RefFnType}; type RefFnType = {readRefEffect: boolean; returnType: RefAccessType}; @@ -82,11 +104,11 @@ export function validateNoRefAccessInRender(fn: HIRFunction): void { validateNoRefAccessInRenderImpl(fn, env).unwrap(); } -function refTypeOfType(identifier: Identifier): RefAccessType { - if (isRefValueType(identifier)) { +function refTypeOfType(place: Place): RefAccessType { + if (isRefValueType(place.identifier)) { return {kind: 'RefValue'}; - } else if (isUseRefType(identifier)) { - return {kind: 'Ref'}; + } else if (isUseRefType(place.identifier)) { + return {kind: 'Ref', refId: nextRefId()}; } else { return {kind: 'None'}; } @@ -101,6 +123,14 @@ function tyEqual(a: RefAccessType, b: RefAccessType): boolean { return true; case 'Ref': return true; + case 'Nullable': + return true; + case 'Guard': + CompilerError.invariant(b.kind === 'Guard', { + reason: 'Expected ref value', + loc: null, + }); + return a.refId === b.refId; case 'RefValue': CompilerError.invariant(b.kind === 'RefValue', { reason: 'Expected ref value', @@ -133,11 +163,17 @@ function joinRefAccessTypes(...types: Array): RefAccessType { b: RefAccessRefType, ): RefAccessRefType { if (a.kind === 'RefValue') { - return a; + if (b.kind === 'RefValue' && a.refId === b.refId) { + return a; + } + return {kind: 'RefValue'}; } else if (b.kind === 'RefValue') { return b; } else if (a.kind === 'Ref' || b.kind === 'Ref') { - return {kind: 'Ref'}; + if (a.kind === 'Ref' && b.kind === 'Ref' && a.refId === b.refId) { + return a; + } + return {kind: 'Ref', refId: nextRefId()}; } else { CompilerError.invariant( a.kind === 'Structure' && b.kind === 'Structure', @@ -178,6 +214,16 @@ function joinRefAccessTypes(...types: Array): RefAccessType { return b; } else if (b.kind === 'None') { return a; + } else if (a.kind === 'Guard' || b.kind === 'Guard') { + if (a.kind === 'Guard' && b.kind === 'Guard' && a.refId === b.refId) { + return a; + } + return {kind: 'None'}; + } else if (a.kind === 'Nullable' || b.kind === 'Nullable') { + if (a.kind === 'Nullable' && b.kind === 'Nullable') { + return a; + } + return {kind: 'None'}; } else { return joinRefAccessRefTypes(a, b); } @@ -198,13 +244,14 @@ function validateNoRefAccessInRenderImpl( } else { place = param.place; } - const type = refTypeOfType(place.identifier); + const type = refTypeOfType(place); env.set(place.identifier.id, type); } for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) { env.resetChanged(); returnValues = []; + const safeBlocks = new Map(); const errors = new CompilerError(); for (const [, block] of fn.body.blocks) { for (const phi of block.phis) { @@ -238,11 +285,15 @@ function validateNoRefAccessInRenderImpl( if (objType?.kind === 'Structure') { lookupType = objType.value; } else if (objType?.kind === 'Ref') { - lookupType = {kind: 'RefValue', loc: instr.loc}; + lookupType = { + kind: 'RefValue', + loc: instr.loc, + refId: objType.refId, + }; } env.set( instr.lvalue.identifier.id, - lookupType ?? refTypeOfType(instr.lvalue.identifier), + lookupType ?? refTypeOfType(instr.lvalue), ); break; } @@ -251,7 +302,7 @@ function validateNoRefAccessInRenderImpl( env.set( instr.lvalue.identifier.id, env.get(instr.value.place.identifier.id) ?? - refTypeOfType(instr.lvalue.identifier), + refTypeOfType(instr.lvalue), ); break; } @@ -260,12 +311,12 @@ function validateNoRefAccessInRenderImpl( env.set( instr.value.lvalue.place.identifier.id, env.get(instr.value.value.identifier.id) ?? - refTypeOfType(instr.value.lvalue.place.identifier), + refTypeOfType(instr.value.lvalue.place), ); env.set( instr.lvalue.identifier.id, env.get(instr.value.value.identifier.id) ?? - refTypeOfType(instr.lvalue.identifier), + refTypeOfType(instr.lvalue), ); break; } @@ -277,13 +328,10 @@ function validateNoRefAccessInRenderImpl( } env.set( instr.lvalue.identifier.id, - lookupType ?? refTypeOfType(instr.lvalue.identifier), + lookupType ?? refTypeOfType(instr.lvalue), ); for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) { - env.set( - lval.identifier.id, - lookupType ?? refTypeOfType(lval.identifier), - ); + env.set(lval.identifier.id, lookupType ?? refTypeOfType(lval)); } break; } @@ -354,7 +402,11 @@ function validateNoRefAccessInRenderImpl( types.push(env.get(operand.identifier.id) ?? {kind: 'None'}); } const value = joinRefAccessTypes(...types); - if (value.kind === 'None') { + if ( + value.kind === 'None' || + value.kind === 'Guard' || + value.kind === 'Nullable' + ) { env.set(instr.lvalue.identifier.id, {kind: 'None'}); } else { env.set(instr.lvalue.identifier.id, { @@ -369,7 +421,18 @@ function validateNoRefAccessInRenderImpl( case 'PropertyStore': case 'ComputedDelete': case 'ComputedStore': { - validateNoRefAccess(errors, env, instr.value.object, instr.loc); + const safe = safeBlocks.get(block.id); + const target = env.get(instr.value.object.identifier.id); + if ( + instr.value.kind === 'PropertyStore' && + safe != null && + target?.kind === 'Ref' && + target.refId === safe + ) { + safeBlocks.delete(block.id); + } else { + validateNoRefAccess(errors, env, instr.value.object, instr.loc); + } for (const operand of eachInstructionValueOperand(instr.value)) { if (operand === instr.value.object) { continue; @@ -381,6 +444,38 @@ function validateNoRefAccessInRenderImpl( case 'StartMemoize': case 'FinishMemoize': break; + case 'Primitive': { + if (instr.value.value == null) { + env.set(instr.lvalue.identifier.id, {kind: 'Nullable'}); + } + break; + } + case 'BinaryExpression': { + const left = env.get(instr.value.left.identifier.id); + const right = env.get(instr.value.right.identifier.id); + let nullish: boolean = false; + let refId: RefId | null = null; + if (left?.kind === 'RefValue' && left.refId != null) { + refId = left.refId; + } else if (right?.kind === 'RefValue' && right.refId != null) { + refId = right.refId; + } + + if (left?.kind === 'Nullable') { + nullish = true; + } else if (right?.kind === 'Nullable') { + nullish = true; + } + + if (refId !== null && nullish) { + env.set(instr.lvalue.identifier.id, {kind: 'Guard', refId}); + } else { + for (const operand of eachInstructionValueOperand(instr.value)) { + validateNoRefValueAccess(errors, env, operand); + } + } + break; + } default: { for (const operand of eachInstructionValueOperand(instr.value)) { validateNoRefValueAccess(errors, env, operand); @@ -388,16 +483,28 @@ function validateNoRefAccessInRenderImpl( break; } } - if (isUseRefType(instr.lvalue.identifier)) { + + // Guard values are derived from ref.current, so they can only be used in if statement targets + for (const operand of eachInstructionOperand(instr)) { + guardCheck(errors, operand, env); + } + + if ( + isUseRefType(instr.lvalue.identifier) && + env.get(instr.lvalue.identifier.id)?.kind !== 'Ref' + ) { env.set( instr.lvalue.identifier.id, joinRefAccessTypes( env.get(instr.lvalue.identifier.id) ?? {kind: 'None'}, - {kind: 'Ref'}, + {kind: 'Ref', refId: nextRefId()}, ), ); } - if (isRefValueType(instr.lvalue.identifier)) { + if ( + isRefValueType(instr.lvalue.identifier) && + env.get(instr.lvalue.identifier.id)?.kind !== 'RefValue' + ) { env.set( instr.lvalue.identifier.id, joinRefAccessTypes( @@ -407,12 +514,24 @@ function validateNoRefAccessInRenderImpl( ); } } + + if (block.terminal.kind === 'if') { + const test = env.get(block.terminal.test.identifier.id); + if (test?.kind === 'Guard') { + safeBlocks.set(block.terminal.consequent, test.refId); + } + } + for (const operand of eachTerminalOperand(block.terminal)) { if (block.terminal.kind !== 'return') { validateNoRefValueAccess(errors, env, operand); + if (block.terminal.kind !== 'if') { + guardCheck(errors, operand, env); + } } else { // Allow functions containing refs to be returned, but not direct ref values validateNoDirectRefValueAccess(errors, operand, env); + guardCheck(errors, operand, env); returnValues.push(env.get(operand.identifier.id)); } } @@ -444,6 +563,23 @@ function destructure( return type; } +function guardCheck(errors: CompilerError, operand: Place, env: Env): void { + if (env.get(operand.identifier.id)?.kind === 'Guard') { + errors.push({ + severity: ErrorSeverity.InvalidReact, + reason: + 'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)', + loc: operand.loc, + description: + operand.identifier.name !== null && + operand.identifier.name.kind === 'named' + ? `Cannot access ref value \`${operand.identifier.name.value}\`` + : null, + suggestions: null, + }); + } +} + function validateNoRefValueAccess( errors: CompilerError, env: Env, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.expect.md new file mode 100644 index 0000000000000..560cef900ffa0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.expect.md @@ -0,0 +1,42 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + +## Code + +```javascript +import { useRef } from "react"; + +function C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + +### Eval output +(kind: ok) \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.js new file mode 100644 index 0000000000000..7c7c3d9cb90ba --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allow-ref-initialization.js @@ -0,0 +1,14 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md new file mode 100644 index 0000000000000..5509375b24699 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.expect.md @@ -0,0 +1,39 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +const DEFAULT_VALUE = 1; + +component C() { + const r = useRef(DEFAULT_VALUE); + if (r.current == DEFAULT_VALUE) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 6 | component C() { + 7 | const r = useRef(DEFAULT_VALUE); +> 8 | if (r.current == DEFAULT_VALUE) { + | ^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (8:8) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9) + 9 | r.current = 1; + 10 | } + 11 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.js new file mode 100644 index 0000000000000..f7e9a9dccb2d3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-arbitrary.js @@ -0,0 +1,16 @@ +//@flow +import {useRef} from 'react'; + +const DEFAULT_VALUE = 1; + +component C() { + const r = useRef(DEFAULT_VALUE); + if (r.current == DEFAULT_VALUE) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md new file mode 100644 index 0000000000000..4adc9e052b96b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + f(r); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 5 | const r = useRef(null); + 6 | if (r.current == null) { +> 7 | f(r); + | ^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (7:7) + 8 | } + 9 | } + 10 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.js new file mode 100644 index 0000000000000..4e5a53cd3f62b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call-2.js @@ -0,0 +1,14 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + f(r); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md new file mode 100644 index 0000000000000..97179bb05da00 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.expect.md @@ -0,0 +1,35 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + f(r.current); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 5 | const r = useRef(null); + 6 | if (r.current == null) { +> 7 | f(r.current); + | ^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (7:7) + 8 | } + 9 | } + 10 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.js new file mode 100644 index 0000000000000..50288fafc4a00 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-call.js @@ -0,0 +1,14 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + f(r.current); + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md new file mode 100644 index 0000000000000..873b4dc8e93c6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.expect.md @@ -0,0 +1,36 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 42; + r.current = 42; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 6 | if (r.current == null) { + 7 | r.current = 42; +> 8 | r.current = 42; + | ^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (8:8) + 9 | } + 10 | } + 11 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.js new file mode 100644 index 0000000000000..23e4952045592 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-linear.js @@ -0,0 +1,15 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 42; + r.current = 42; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md new file mode 100644 index 0000000000000..9cba870e72cd6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.expect.md @@ -0,0 +1,38 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + const guard = r.current == null; + if (guard) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 4 | component C() { + 5 | const r = useRef(null); +> 6 | const guard = r.current == null; + | ^^^^^^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (6:6) + +InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef). Cannot access ref value `guard` (7:7) + 7 | if (guard) { + 8 | r.current = 1; + 9 | } +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.js new file mode 100644 index 0000000000000..94216b3bacb32 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-nonif.js @@ -0,0 +1,15 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + const guard = r.current == null; + if (guard) { + r.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md new file mode 100644 index 0000000000000..c24682e27161d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.expect.md @@ -0,0 +1,36 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + const r2 = useRef(null); + if (r.current == null) { + r2.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 6 | const r2 = useRef(null); + 7 | if (r.current == null) { +> 8 | r2.current = 1; + | ^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (8:8) + 9 | } + 10 | } + 11 | +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.js new file mode 100644 index 0000000000000..58abd12ac80cb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-other.js @@ -0,0 +1,15 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + const r2 = useRef(null); + if (r.current == null) { + r2.current = 1; + } +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md new file mode 100644 index 0000000000000..90dbcab06ee1e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.expect.md @@ -0,0 +1,36 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } + f(r.current); +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 7 | r.current = 1; + 8 | } +> 9 | f(r.current); + | ^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9) + 10 | } + 11 | + 12 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.js new file mode 100644 index 0000000000000..a8e3b124bfeb6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access-2.js @@ -0,0 +1,15 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } + f(r.current); +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md new file mode 100644 index 0000000000000..ca10ca5750e55 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.expect.md @@ -0,0 +1,36 @@ + +## Input + +```javascript +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } + r.current = 1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; + +``` + + +## Error + +``` + 7 | r.current = 1; + 8 | } +> 9 | r.current = 1; + | ^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (9:9) + 10 | } + 11 | + 12 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.js new file mode 100644 index 0000000000000..ba476e6e422e1 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-initialization-post-access.js @@ -0,0 +1,15 @@ +//@flow +import {useRef} from 'react'; + +component C() { + const r = useRef(null); + if (r.current == null) { + r.current = 1; + } + r.current = 1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: C, + params: [{}], +}; From 147374d71a73f3f63ff6532dc081d1175f783352 Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 11 Oct 2024 16:19:45 -0700 Subject: [PATCH 272/426] [compiler] Kill markReactiveIdentifier and friends Summary: With the previous PR we no longer need to mark identifiers as reactive in contexts where we don't have places. We already deleted most uses of markReactiveId; the last case was to track identifiers through loadlocals etc -- but we already use a disjoint alias map that accounts for loadlocals when setting reactivity. ghstack-source-id: 69ce0a78b0729da3fe9d08177bf7d827af5325fb Pull Request resolved: https://github.com/facebook/react/pull/31178 --- .../src/Inference/InferReactivePlaces.ts | 46 ++----------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts index 98b1ec75e1337..344949b020a99 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Inference/InferReactivePlaces.ts @@ -157,7 +157,6 @@ export function inferReactivePlaces(fn: HIRFunction): void { } do { - const identifierMapping = new Map(); for (const [, block] of fn.body.blocks) { let hasReactiveControl = isReactiveControlledBlock(block.id); @@ -233,10 +232,6 @@ export function inferReactivePlaces(fn: HIRFunction): void { case Effect.ConditionallyMutate: case Effect.Mutate: { if (isMutable(instruction, operand)) { - const resolvedId = identifierMapping.get(operand.identifier); - if (resolvedId !== undefined) { - reactiveIdentifiers.markReactiveIdentifier(resolvedId); - } reactiveIdentifiers.markReactive(operand); } break; @@ -263,31 +258,6 @@ export function inferReactivePlaces(fn: HIRFunction): void { } } } - - switch (value.kind) { - case 'LoadLocal': { - identifierMapping.set( - instruction.lvalue.identifier, - value.place.identifier, - ); - break; - } - case 'PropertyLoad': - case 'ComputedLoad': { - const resolvedId = - identifierMapping.get(value.object.identifier) ?? - value.object.identifier; - identifierMapping.set(instruction.lvalue.identifier, resolvedId); - break; - } - case 'LoadContext': { - identifierMapping.set( - instruction.lvalue.identifier, - value.place.identifier, - ); - break; - } - } } for (const operand of eachTerminalOperand(block.terminal)) { reactiveIdentifiers.isReactive(operand); @@ -372,27 +342,19 @@ class ReactivityMap { } isReactive(place: Place): boolean { - const reactive = this.isReactiveIdentifier(place.identifier); + const identifier = + this.aliasedIdentifiers.find(place.identifier) ?? place.identifier; + const reactive = this.reactive.has(identifier.id); if (reactive) { place.reactive = true; } return reactive; } - isReactiveIdentifier(inputIdentifier: Identifier): boolean { - const identifier = - this.aliasedIdentifiers.find(inputIdentifier) ?? inputIdentifier; - return this.reactive.has(identifier.id); - } - markReactive(place: Place): void { place.reactive = true; - this.markReactiveIdentifier(place.identifier); - } - - markReactiveIdentifier(inputIdentifier: Identifier): void { const identifier = - this.aliasedIdentifiers.find(inputIdentifier) ?? inputIdentifier; + this.aliasedIdentifiers.find(place.identifier) ?? place.identifier; if (!this.reactive.has(identifier.id)) { this.hasChanges = true; this.reactive.add(identifier.id); From cd22717c274061fd7dc13cd6eaff10e6a3946508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 13 Oct 2024 12:57:50 -0400 Subject: [PATCH 273/426] [Flight] Also don't cut off type and key (#31209) --- packages/react-client/src/ReactFlightClient.js | 6 ++---- packages/react-server/src/ReactFlightServer.js | 11 +++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 2f60ccddb4b4d..141058fb9dfb2 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -1364,10 +1364,8 @@ function parseModelString( // happened. Object.defineProperty(parentObject, key, { get: function () { - // We intentionally don't throw an error object here because it looks better - // without the stack in the console which isn't useful anyway. - // eslint-disable-next-line no-throw-literal - throw ( + // TODO: We should ideally throw here to indicate a difference. + return ( 'This object has been omitted by React in the console log ' + 'to avoid sending too much data from the server. Try logging smaller ' + 'or more specific objects.' diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 6adf619290e5e..ca004a6e7971f 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -3465,7 +3465,18 @@ function renderConsoleValue( if (element._owner != null) { outlineComponentInfo(request, element._owner); } + if (typeof element.type === 'object' && element.type !== null) { + // If the type is an object it can get cut off which shouldn't happen here. + doNotLimit.add(element.type); + } + if (typeof element.key === 'object' && element.key !== null) { + // This should never happen but just in case. + doNotLimit.add(element.key); + } doNotLimit.add(element.props); + if (element._owner !== null) { + doNotLimit.add(element._owner); + } if (enableOwnerStacks) { let debugStack: null | ReactStackTrace = null; From 75dd053b5e83e8ae20e9f771bca7b95dba4ff881 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Mon, 14 Oct 2024 10:13:40 -0400 Subject: [PATCH 274/426] [string-refs] make disableStringRefs a dynamic www flag (#31175) --- packages/shared/forks/ReactFeatureFlags.www-dynamic.js | 1 + packages/shared/forks/ReactFeatureFlags.www.js | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 3888339bff2ed..d4102efb06bcd 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -18,6 +18,7 @@ export const disableDefaultPropsExceptForClasses = __VARIANT__; export const disableLegacyContextForFunctionComponents = __VARIANT__; export const disableLegacyMode = __VARIANT__; export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; +export const disableStringRefs = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__; export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 7484832a68b40..ec572d86f5ae4 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -19,6 +19,7 @@ export const { disableDefaultPropsExceptForClasses, disableLegacyContextForFunctionComponents, disableSchedulerTimeoutInWorkLoop, + disableStringRefs, enableDebugTracing, enableDeferRootSchedulingToMicrotask, enableDO_NOT_USE_disableStrictPassiveEffect, @@ -120,10 +121,6 @@ export const enableServerComponentLogs = true; export const enableReactTestRendererWarning = false; export const useModernStrictMode = true; -// TODO: Roll out with GK. Don't keep as dynamic flag for too long, though, -// because JSX is an extremely hot path. -export const disableStringRefs = false; - export const disableLegacyMode: boolean = __EXPERIMENTAL__ || dynamicFeatureFlags.disableLegacyMode; From b60286b8349e79f025103b9d106458ed667d9914 Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 14 Oct 2024 11:20:47 -0400 Subject: [PATCH 275/426] [compiler] Use consistent version hash for npm (#31177) Modifies our release script to use the same version hash (the hashed `compiler` directory) for all compiler packages to keep them consistent. --- compiler/scripts/release/publish.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/scripts/release/publish.js b/compiler/scripts/release/publish.js index 928994e1e4892..ef3b75a80fe6f 100755 --- a/compiler/scripts/release/publish.js +++ b/compiler/scripts/release/publish.js @@ -119,6 +119,13 @@ async function main() { ); const dateString = await getDateStringForCommit(commit); const otp = argv.ci === false ? await promptForOTP() : null; + const {hash} = await hashElement(path.resolve(__dirname, '../..'), { + encoding: 'hex', + folders: {exclude: ['node_modules']}, + files: {exclude: ['.DS_Store']}, + }); + const truncatedHash = hash.slice(0, 7); + const newVersion = `0.0.0-experimental-${truncatedHash}-${dateString}`; for (const pkgName of pkgNames) { const pkgDir = path.resolve(__dirname, `../../packages/${pkgName}`); @@ -126,13 +133,6 @@ async function main() { __dirname, `../../packages/${pkgName}/package.json` ); - const {hash} = await hashElement(pkgDir, { - encoding: 'hex', - folders: {exclude: ['node_modules']}, - files: {exclude: ['.DS_Store']}, - }); - const truncatedHash = hash.slice(0, 7); - const newVersion = `0.0.0-experimental-${truncatedHash}-${dateString}`; spinner.start(`Writing package.json for ${pkgName}@${newVersion}`); await writeJson( From cbcc1d2027c1d77abdf934b7f5e645882ffa4195 Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 14 Oct 2024 12:07:08 -0400 Subject: [PATCH 276/426] [ci] Consistent cache names (#31239) Makes cache names more descriptive and consistent for CI, so it's easier to tell which cache is used for what purpose. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31239). * #31240 * __->__ #31239 --- .github/workflows/compiler_playground.yml | 2 +- .github/workflows/compiler_prereleases.yml | 2 +- .github/workflows/compiler_typescript.yml | 6 ++-- .../workflows/devtools_regression_tests.yml | 8 +++--- .github/workflows/runtime_build_and_test.yml | 28 +++++++++---------- .../workflows/runtime_commit_artifacts.yml | 2 +- .github/workflows/runtime_prereleases.yml | 2 +- .github/workflows/shared_lint.yml | 8 +++--- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index d7a6306ee4318..645326e55c64b 100644 --- a/.github/workflows/compiler_playground.yml +++ b/.github/workflows/compiler_playground.yml @@ -33,7 +33,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('compiler/**/yarn.lock') }} + key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} - name: yarn install compiler run: yarn install --frozen-lockfile working-directory: compiler diff --git a/.github/workflows/compiler_prereleases.yml b/.github/workflows/compiler_prereleases.yml index 25ad6adde8861..c2b09dae054db 100644 --- a/.github/workflows/compiler_prereleases.yml +++ b/.github/workflows/compiler_prereleases.yml @@ -44,7 +44,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('compiler/**/yarn.lock') }} + key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} - run: yarn install --frozen-lockfile - name: Publish packages to npm run: | diff --git a/.github/workflows/compiler_typescript.yml b/.github/workflows/compiler_typescript.yml index 6fc00047a16f2..327fb19d33399 100644 --- a/.github/workflows/compiler_typescript.yml +++ b/.github/workflows/compiler_typescript.yml @@ -43,7 +43,7 @@ jobs: uses: actions/cache@v4 with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('compiler/**/yarn.lock') }} + key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn workspace babel-plugin-react-compiler lint @@ -63,7 +63,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('compiler/**/yarn.lock') }} + key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn workspace babel-plugin-react-compiler jest @@ -87,6 +87,6 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('compiler/**/yarn.lock') }} + key: compiler-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn workspace ${{ matrix.workspace_name }} test diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml index 1183d062d1abe..be4c38e25612b 100644 --- a/.github/workflows/devtools_regression_tests.yml +++ b/.github/workflows/devtools_regression_tests.yml @@ -30,7 +30,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile working-directory: scripts/release @@ -62,7 +62,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -116,7 +116,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore all archived build artifacts uses: actions/download-artifact@v4 @@ -150,7 +150,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore all archived build artifacts uses: actions/download-artifact@v4 diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index 1f780d4ee37c4..cce2f8359e3f0 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -48,7 +48,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }} @@ -68,7 +68,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: | yarn generate-inline-fizz-runtime @@ -90,7 +90,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn flags @@ -139,7 +139,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }} @@ -168,7 +168,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn build --index=${{ matrix.worker_id }} --total=20 --r=${{ matrix.release_channel }} --ci env: @@ -238,7 +238,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -266,7 +266,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -309,7 +309,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -340,7 +340,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -368,7 +368,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: v2-yarn_cache_fixtures_dom-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + key: fixtures_dom-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn working-directory: fixtures/dom @@ -408,7 +408,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: v2-yarn_cache_fixtures_flight-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + key: fixtures_flight-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -464,7 +464,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -510,7 +510,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -581,7 +581,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - run: yarn install --frozen-lockfile - name: Restore archived build for PR uses: actions/download-artifact@v4 diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index b8b21eb288d40..7842f07ba5888 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -74,7 +74,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} - run: yarn install --frozen-lockfile name: yarn install (react) - run: yarn install --frozen-lockfile diff --git a/.github/workflows/runtime_prereleases.yml b/.github/workflows/runtime_prereleases.yml index 0f3f79432b5c2..37516ea3cb19c 100644 --- a/.github/workflows/runtime_prereleases.yml +++ b/.github/workflows/runtime_prereleases.yml @@ -40,7 +40,7 @@ jobs: id: node_modules with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile working-directory: scripts/release diff --git a/.github/workflows/shared_lint.yml b/.github/workflows/shared_lint.yml index 31834c3fb9688..6d3b75d2ab29c 100644 --- a/.github/workflows/shared_lint.yml +++ b/.github/workflows/shared_lint.yml @@ -25,7 +25,7 @@ jobs: uses: actions/cache@v4 with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: yarn prettier-check @@ -43,7 +43,7 @@ jobs: uses: actions/cache@v4 with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: node ./scripts/tasks/eslint @@ -61,7 +61,7 @@ jobs: uses: actions/cache@v4 with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: ./scripts/ci/check_license.sh @@ -79,6 +79,6 @@ jobs: uses: actions/cache@v4 with: path: "**/node_modules" - key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - run: yarn install --frozen-lockfile - run: ./scripts/ci/test_print_warnings.sh From 6cf8518505b198c58c950976174b1642760d48ee Mon Sep 17 00:00:00 2001 From: lauren Date: Mon, 14 Oct 2024 12:07:24 -0400 Subject: [PATCH 277/426] [ci] Specify limited concurrency for PR jobs (#31240) There was a concurrency setting we hadn't enabled on jobs that are primarily triggered for PRs. This meant that every update to the PR would trigger new CI jobs without canceling any ones already in flight, which can greatly slow down CI due to the number of jobs that need to run. This PR adds concurrency [based on the workflow name and PR number or head ref.](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs) --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31240). * __->__ #31240 * #31239 --- .github/workflows/compiler_playground.yml | 4 ++++ .github/workflows/compiler_rust.yml | 4 ++++ .github/workflows/compiler_typescript.yml | 4 ++++ .github/workflows/runtime_build_and_test.yml | 4 ++++ .github/workflows/shared_lint.yml | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index 645326e55c64b..338a95d208a9b 100644 --- a/.github/workflows/compiler_playground.yml +++ b/.github/workflows/compiler_playground.yml @@ -8,6 +8,10 @@ on: - compiler/** - .github/workflows/compiler-playground.yml +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + cancel-in-progress: true + env: TZ: /usr/share/zoneinfo/America/Los_Angeles # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout diff --git a/.github/workflows/compiler_rust.yml b/.github/workflows/compiler_rust.yml index 3cda1325ca49e..6b4a023a298a0 100644 --- a/.github/workflows/compiler_rust.yml +++ b/.github/workflows/compiler_rust.yml @@ -15,6 +15,10 @@ on: - compiler/Cargo.* - compiler/*.toml +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always RUSTFLAGS: -Dwarnings diff --git a/.github/workflows/compiler_typescript.yml b/.github/workflows/compiler_typescript.yml index 327fb19d33399..acd23eeb956c2 100644 --- a/.github/workflows/compiler_typescript.yml +++ b/.github/workflows/compiler_typescript.yml @@ -8,6 +8,10 @@ on: - compiler/** - .github/workflows/compiler_typescript.yml +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + cancel-in-progress: true + env: TZ: /usr/share/zoneinfo/America/Los_Angeles # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index cce2f8359e3f0..1a85eb408461b 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -7,6 +7,10 @@ on: paths-ignore: - compiler/** +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + cancel-in-progress: true + env: TZ: /usr/share/zoneinfo/America/Los_Angeles # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout diff --git a/.github/workflows/shared_lint.yml b/.github/workflows/shared_lint.yml index 6d3b75d2ab29c..a3608ec291e63 100644 --- a/.github/workflows/shared_lint.yml +++ b/.github/workflows/shared_lint.yml @@ -5,6 +5,10 @@ on: branches: [main] pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + cancel-in-progress: true + env: TZ: /usr/share/zoneinfo/America/Los_Angeles # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cache-segment-restore-timeout From 13411e4589f3d999727c5322781e2dd7bef3b256 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 14 Oct 2024 14:12:23 -0400 Subject: [PATCH 278/426] [Re-land] Make prerendering always non-blocking: Add missing feature flag checks (#31238) This is a partial re-land of https://github.com/facebook/react/pull/31056. We saw breakages surface after the original land and had to revert. Now that they've been fixed, let's try this again. This time we'll split up the commits to give us more control of testing and rollout internally. Original PR: https://github.com/facebook/react/pull/31056 Original Commit: https://github.com/facebook/react/pull/31056/commits/2a9fb445d98b60a97f3642cec2ff22469727e0c7 Revert PR: https://github.com/facebook/react/pull/31080 Commit description: ``` Neglected to wrap some places in the enableSiblingPrerendering flag. ``` Co-authored-by: Andrew Clark --- .../src/ReactFiberCompleteWork.js | 5 +++- .../react-reconciler/src/ReactFiberLane.js | 28 +++++++++++-------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index e3fba900dd116..b24351ac383b9 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -42,6 +42,7 @@ import { enableRenderableContext, passChildrenWhenCloningPersistedNodes, disableLegacyMode, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import {now} from './Scheduler'; @@ -622,7 +623,9 @@ function scheduleRetryEffect( // Track the lanes that have been scheduled for an immediate retry so that // we can mark them as suspended upon committing the root. - markSpawnedRetryLane(retryLane); + if (enableSiblingPrerendering) { + markSpawnedRetryLane(retryLane); + } } } diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index b8c051def4eef..7d6bfd16e8aa0 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -27,6 +27,7 @@ import { transitionLaneExpirationMs, retryLaneExpirationMs, disableLegacyMode, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import {isDevToolsPresent} from './ReactFiberDevToolsHook'; import {clz32} from './clz32'; @@ -270,11 +271,13 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (nonIdlePingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); } else { - // Nothing has been pinged. Check for lanes that need to be prewarmed. - if (!rootHasPendingCommit) { - const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes; - if (lanesToPrewarm !== NoLanes) { - nextLanes = getHighestPriorityLanes(lanesToPrewarm); + if (enableSiblingPrerendering) { + // Nothing has been pinged. Check for lanes that need to be prewarmed. + if (!rootHasPendingCommit) { + const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes; + if (lanesToPrewarm !== NoLanes) { + nextLanes = getHighestPriorityLanes(lanesToPrewarm); + } } } } @@ -294,11 +297,13 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (pingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(pingedLanes); } else { - // Nothing has been pinged. Check for lanes that need to be prewarmed. - if (!rootHasPendingCommit) { - const lanesToPrewarm = pendingLanes & ~warmLanes; - if (lanesToPrewarm !== NoLanes) { - nextLanes = getHighestPriorityLanes(lanesToPrewarm); + if (enableSiblingPrerendering) { + // Nothing has been pinged. Check for lanes that need to be prewarmed. + if (!rootHasPendingCommit) { + const lanesToPrewarm = pendingLanes & ~warmLanes; + if (lanesToPrewarm !== NoLanes) { + nextLanes = getHighestPriorityLanes(lanesToPrewarm); + } } } } @@ -765,7 +770,7 @@ export function markRootSuspended( root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; - if (!didSkipSuspendedSiblings) { + if (enableSiblingPrerendering && !didSkipSuspendedSiblings) { // Mark these lanes as warm so we know there's nothing else to work on. root.warmLanes |= suspendedLanes; } else { @@ -876,6 +881,7 @@ export function markRootFinished( // suspended) instead of the regular mode (i.e. unwind and skip the siblings // as soon as something suspends to unblock the rest of the update). if ( + enableSiblingPrerendering && suspendedRetryLanes !== NoLanes && // Note that we only do this if there were no updates since we started // rendering. This mirrors the logic in markRootUpdated — whenever we From ec2bf022450107a77cc2850ec96b9173fc6f40eb Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 15 Oct 2024 12:46:05 +0100 Subject: [PATCH 279/426] fix[react-devtools]: fixed timeline profiler tests (#31261) Fixes tests against React 18 after https://github.com/facebook/react/pull/31154: - Set `supportsTimeline` to true for `Store`. - Execute `store.profilerStore.startProfiling` after `legacyRender` import, because this is where `react-dom` is imported and renderer is registered. We don't yet propagate `isProfiling` flag to newly registered renderers, when profiling already started see: https://github.com/facebook/react/blob/d5bba18b5d81f234657586865248c5b6849599cd/packages/react-devtools-shared/src/hook.js#L203-L204 --- .../src/__tests__/TimelineProfiler-test.js | 12 ++++++++---- .../src/__tests__/setupTests.js | 4 +++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js b/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js index b4cc9bbc0bafc..e632227ab3a79 100644 --- a/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js +++ b/packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js @@ -1280,13 +1280,13 @@ describe('Timeline profiler', () => { }); describe('when profiling', () => { - beforeEach(() => { - utils.act(() => store.profilerStore.startProfiling()); - }); - describe('with legacy render', () => { const {render: legacyRender} = getLegacyRenderImplementation(); + beforeEach(() => { + utils.act(() => store.profilerStore.startProfiling()); + }); + // @reactVersion <= 18.2 // @reactVersion >= 18.0 it('should mark sync render without suspends or state updates', () => { @@ -1537,6 +1537,10 @@ describe('Timeline profiler', () => { const {render: modernRender} = getModernRenderImplementation(); + beforeEach(() => { + utils.act(() => store.profilerStore.startProfiling()); + }); + it('should mark concurrent render without suspends or state updates', () => { utils.act(() => modernRender(
)); diff --git a/packages/react-devtools-shared/src/__tests__/setupTests.js b/packages/react-devtools-shared/src/__tests__/setupTests.js index 0a821345fcbac..50431b230ad87 100644 --- a/packages/react-devtools-shared/src/__tests__/setupTests.js +++ b/packages/react-devtools-shared/src/__tests__/setupTests.js @@ -256,7 +256,9 @@ beforeEach(() => { }, }); - const store = new Store(((bridge: any): FrontendBridge)); + const store = new Store(((bridge: any): FrontendBridge), { + supportsTimeline: true, + }); const agent = new Agent(((bridge: any): BackendBridge)); const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__; From 9806a4b0d4e659863f3f04d32da50f545c7199a8 Mon Sep 17 00:00:00 2001 From: lauren Date: Tue, 15 Oct 2024 07:53:45 -0400 Subject: [PATCH 280/426] [DevTools] Fix React Compiler badging (#31196) In #31140 we switched over the uMC polyfill to use memo instead of state since memo would FastRefresh properly. However this busted devtools' badging of compiled components; this PR fixes it. TODO: tests Co-authored-by: Ruslan Lesiutin --------- Co-authored-by: Ruslan Lesiutin --- packages/react-devtools-shared/src/backend/fiber/renderer.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index d582e2a3ced96..e1bd7881326cf 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -599,6 +599,8 @@ export function getInternalReactConstants(version: string): { !shouldSkipForgetCheck && // $FlowFixMe[incompatible-type] fiber.updateQueue is mixed (fiber.updateQueue?.memoCache != null || + (Array.isArray(fiber.memoizedState?.memoizedState) && + fiber.memoizedState.memoizedState[0]?.[REACT_MEMO_CACHE_SENTINEL]) || fiber.memoizedState?.memoizedState?.[REACT_MEMO_CACHE_SENTINEL]) ) { const displayNameWithoutForgetWrapper = getDisplayNameForFiber( From c7c68ef842639f8535942b6247ef758221d289fb Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Tue, 15 Oct 2024 14:15:26 +0100 Subject: [PATCH 281/426] React DevTools 6.0.0 -> 6.0.1 (#31263) Changes in this release: * Fix React Compiler badging ([poteto](https://github.com/poteto) in [#31196](https://github.com/facebook/react/pull/31196)) * fix[react-devtools]: fixed timeline profiler tests ([hoxyq](https://github.com/hoxyq) in [#31261](https://github.com/facebook/react/pull/31261)) * fix[react-devtools]: record timeline data only when supported ([hoxyq](https://github.com/hoxyq) in [#31154](https://github.com/facebook/react/pull/31154)) * refactor[react-devtools]: flatten reload and profile config ([hoxyq](https://github.com/hoxyq) in [#31132](https://github.com/facebook/react/pull/31132)) * fix[react-devtools]: remove all listeners when Agent is shutdown ([hoxyq](https://github.com/hoxyq) in [#31151](https://github.com/facebook/react/pull/31151)) * fix[react-devtools]: removed redundant startProfiling call ([hoxyq](https://github.com/hoxyq) in [#31131](https://github.com/facebook/react/pull/31131)) * refactor[react-devtools/fiber/renderer]: optimize durations resolution ([hoxyq](https://github.com/hoxyq) in [#31118](https://github.com/facebook/react/pull/31118)) * fix[react-devtools]: update profiling status before receiving response from backend ([hoxyq](https://github.com/hoxyq) in [#31117](https://github.com/facebook/react/pull/31117)) * fix[react-devtools]: wrap key string in preformatted text html element ([hoxyq](https://github.com/hoxyq) in [#31153](https://github.com/facebook/react/pull/31153)) * chore[react-devtools]: drop legacy context tests ([hoxyq](https://github.com/hoxyq) in [#31059](https://github.com/facebook/react/pull/31059)) * chore[react-devtools]: add legacy mode error message to the ignore list for tests ([hoxyq](https://github.com/hoxyq) in [#31060](https://github.com/facebook/react/pull/31060)) * fix[react-devtools]: request hook initialization inside http server response ([hoxyq](https://github.com/hoxyq) in [#31102](https://github.com/facebook/react/pull/31102)) * [Flight] Serialize Server Components Props in DEV ([sebmarkbage](https://github.com/sebmarkbage) in [#31105](https://github.com/facebook/react/pull/31105)) * Add: reload to profile for Fusebox ([EdmondChuiHW](https://github.com/EdmondChuiHW) in [#31021](https://github.com/facebook/react/pull/31021)) * refactor: allow custom impl of backend realod-to-profile support check ([EdmondChuiHW](https://github.com/EdmondChuiHW) in [#31048](https://github.com/facebook/react/pull/31048)) * fix: use public instance in Fiber renderer and expose it from getInspectorDataForViewAtPoint ([hoxyq](https://github.com/hoxyq) in [#31068](https://github.com/facebook/react/pull/31068)) --- packages/react-devtools-core/package.json | 2 +- .../react-devtools-extensions/chrome/manifest.json | 4 ++-- .../react-devtools-extensions/edge/manifest.json | 4 ++-- .../react-devtools-extensions/firefox/manifest.json | 2 +- packages/react-devtools-inline/package.json | 2 +- packages/react-devtools-timeline/package.json | 2 +- packages/react-devtools/CHANGELOG.md | 12 ++++++++++++ packages/react-devtools/package.json | 4 ++-- 8 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/react-devtools-core/package.json b/packages/react-devtools-core/package.json index 23167fa377847..c2d3b0e58afff 100644 --- a/packages/react-devtools-core/package.json +++ b/packages/react-devtools-core/package.json @@ -1,6 +1,6 @@ { "name": "react-devtools-core", - "version": "6.0.0", + "version": "6.0.1", "description": "Use react-devtools outside of the browser", "license": "MIT", "main": "./dist/backend.js", diff --git a/packages/react-devtools-extensions/chrome/manifest.json b/packages/react-devtools-extensions/chrome/manifest.json index f0209aaa73eed..7f29a597029a2 100644 --- a/packages/react-devtools-extensions/chrome/manifest.json +++ b/packages/react-devtools-extensions/chrome/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Chrome Developer Tools.", - "version": "6.0.0", - "version_name": "6.0.0", + "version": "6.0.1", + "version_name": "6.0.1", "minimum_chrome_version": "102", "icons": { "16": "icons/16-production.png", diff --git a/packages/react-devtools-extensions/edge/manifest.json b/packages/react-devtools-extensions/edge/manifest.json index ca4d56b4453e9..dcf1448b087e0 100644 --- a/packages/react-devtools-extensions/edge/manifest.json +++ b/packages/react-devtools-extensions/edge/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Microsoft Edge Developer Tools.", - "version": "6.0.0", - "version_name": "6.0.0", + "version": "6.0.1", + "version_name": "6.0.1", "minimum_chrome_version": "102", "icons": { "16": "icons/16-production.png", diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json index 52f89104b4f80..98c8079546efb 100644 --- a/packages/react-devtools-extensions/firefox/manifest.json +++ b/packages/react-devtools-extensions/firefox/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Firefox Developer Tools.", - "version": "6.0.0", + "version": "6.0.1", "browser_specific_settings": { "gecko": { "id": "@react-devtools", diff --git a/packages/react-devtools-inline/package.json b/packages/react-devtools-inline/package.json index f0eadaf7e6d9e..d601f095a7d7e 100644 --- a/packages/react-devtools-inline/package.json +++ b/packages/react-devtools-inline/package.json @@ -1,6 +1,6 @@ { "name": "react-devtools-inline", - "version": "6.0.0", + "version": "6.0.1", "description": "Embed react-devtools within a website", "license": "MIT", "main": "./dist/backend.js", diff --git a/packages/react-devtools-timeline/package.json b/packages/react-devtools-timeline/package.json index 883aad785f6b2..306b458f3860d 100644 --- a/packages/react-devtools-timeline/package.json +++ b/packages/react-devtools-timeline/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "react-devtools-timeline", - "version": "6.0.0", + "version": "6.0.1", "license": "MIT", "dependencies": { "@elg/speedscope": "1.9.0-a6f84db", diff --git a/packages/react-devtools/CHANGELOG.md b/packages/react-devtools/CHANGELOG.md index aab41edf090f3..565eb8869fb31 100644 --- a/packages/react-devtools/CHANGELOG.md +++ b/packages/react-devtools/CHANGELOG.md @@ -4,6 +4,18 @@ --- +### 6.0.1 +October 15, 2024 + +* Fix React Compiler badging ([poteto](https://github.com/poteto) in [#31196](https://github.com/facebook/react/pull/31196)) +* fix[react-devtools]: record timeline data only when supported ([hoxyq](https://github.com/hoxyq) in [#31154](https://github.com/facebook/react/pull/31154)) +* fix[react-devtools]: remove all listeners when Agent is shutdown ([hoxyq](https://github.com/hoxyq) in [#31151](https://github.com/facebook/react/pull/31151)) +* fix[react-devtools]: wrap key string in preformatted text html element ([hoxyq](https://github.com/hoxyq) in [#31153](https://github.com/facebook/react/pull/31153)) +* fix[react-devtools]: request hook initialization inside http server response ([hoxyq](https://github.com/hoxyq) in [#31102](https://github.com/facebook/react/pull/31102)) +* refactor: allow custom impl of backend reload-to-profile support check ([EdmondChuiHW](https://github.com/EdmondChuiHW) in [#31048](https://github.com/facebook/react/pull/31048)) + +--- + ### 6.0.0 September 25, 2024 diff --git a/packages/react-devtools/package.json b/packages/react-devtools/package.json index 0972fd8c94e7a..fa7b80d4d0c63 100644 --- a/packages/react-devtools/package.json +++ b/packages/react-devtools/package.json @@ -1,6 +1,6 @@ { "name": "react-devtools", - "version": "6.0.0", + "version": "6.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": "6.0.0", + "react-devtools-core": "6.0.1", "update-notifier": "^2.1.0" } } From 838258144652ab2ef0cbe54d03e9bdd454348d48 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Tue, 15 Oct 2024 17:17:41 +0200 Subject: [PATCH 282/426] [ESLint] Add test for rejected `useId` in async Components (#31208) --- .../__tests__/ESLintRulesOfHooks-test.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js index a98d2b76961f7..a1e4c49e15573 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js @@ -1129,6 +1129,34 @@ const tests = { `, errors: [asyncComponentHookError('useState')], }, + { + code: normalizeIndent` + async function Page() { + useId(); + React.useId(); + } + `, + errors: [ + asyncComponentHookError('useId'), + asyncComponentHookError('React.useId'), + ], + }, + { + code: normalizeIndent` + async function useAsyncHook() { + useId(); + } + `, + errors: [asyncComponentHookError('useId')], + }, + { + code: normalizeIndent` + async function notAHook() { + useId(); + } + `, + errors: [functionError('useId', 'notAHook')], + }, { code: normalizeIndent` Hook.use(); From 6c4bbc783286bf6eebd9927cb52e8fec5ad4dd74 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Tue, 15 Oct 2024 16:47:02 -0400 Subject: [PATCH 283/426] [Re-land] Make prerendering always non-blocking (#31268) Follows https://github.com/facebook/react/pull/31238 ___ This is a partial re-land of https://github.com/facebook/react/pull/31056. We saw breakages surface after the original land and had to revert. Now that they've been fixed, let's try this again. This time we'll split up the commits to give us more control of testing and rollout internally. Original PR: https://github.com/facebook/react/pull/31056 Original Commit: https://github.com/facebook/react/pull/31056/commits/4c71025d8d1bd46344ad793e7ed3049d24f7395a Revert PR: https://github.com/facebook/react/pull/31080 Commit description: > When a synchronous update suspends, and we prerender the siblings, the prerendering should be non-blocking so that we can immediately restart once the data arrives. > > This happens automatically when there's a Suspense boundary, because we immediately commit the boundary and then proceed to a Retry render, which are always concurrent. When there's not a Suspense boundary, there is no Retry, so we need to take care to switch from the synchronous work loop to the concurrent one, to enable time slicing. Co-authored-by: Andrew Clark --- .../src/__tests__/ReactDOMFiberAsync-test.js | 2 +- .../react-reconciler/src/ReactFiberLane.js | 6 +- .../src/ReactFiberRootScheduler.js | 20 +- .../src/ReactFiberWorkLoop.js | 293 +++++++++++------- .../src/__tests__/ReactDeferredValue-test.js | 12 + .../ReactSiblingPrerendering-test.js | 71 +++++ 6 files changed, 278 insertions(+), 126 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index ee843996bef1c..027099d54707c 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -744,7 +744,7 @@ describe('ReactDOMFiberAsync', () => { // Because it suspended, it remains on the current path expect(div.textContent).toBe('/path/a'); }); - assertLog([]); + assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []); await act(async () => { resolvePromise(); diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index 7d6bfd16e8aa0..b98019046e3c2 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -765,12 +765,14 @@ export function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didSkipSuspendedSiblings: boolean, + didAttemptEntireTree: boolean, ) { + // TODO: Split this into separate functions for marking the root at the end of + // a render attempt versus suspending while the root is still in progress. root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; - if (enableSiblingPrerendering && !didSkipSuspendedSiblings) { + if (enableSiblingPrerendering && didAttemptEntireTree) { // Mark these lanes as warm so we know there's nothing else to work on. root.warmLanes |= suspendedLanes; } else { diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 9f267e8345e39..39f6f466ed983 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -18,6 +18,7 @@ import { disableSchedulerTimeoutInWorkLoop, enableProfilerTimer, enableProfilerNestedUpdatePhase, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import { NoLane, @@ -29,6 +30,7 @@ import { markStarvedLanesAsExpired, claimNextTransitionLane, getNextLanesToFlushSync, + checkIfRootIsPrerendering, } from './ReactFiberLane'; import { CommitContext, @@ -206,7 +208,10 @@ function flushSyncWorkAcrossRoots_impl( ? workInProgressRootRenderLanes : NoLanes, ); - if (includesSyncLane(nextLanes)) { + if ( + includesSyncLane(nextLanes) && + !checkIfRootIsPrerendering(root, nextLanes) + ) { // This root has pending sync work. Flush it now. didPerformSomeWork = true; performSyncWorkOnRoot(root, nextLanes); @@ -341,7 +346,13 @@ function scheduleTaskForRootDuringMicrotask( } // Schedule a new callback in the host environment. - if (includesSyncLane(nextLanes)) { + if ( + includesSyncLane(nextLanes) && + // If we're prerendering, then we should use the concurrent work loop + // even if the lanes are synchronous, so that prerendering never blocks + // the main thread. + !(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes)) + ) { // Synchronous work is always flushed at the end of the microtask, so we // don't need to schedule an additional task. if (existingCallbackNode !== null) { @@ -375,9 +386,10 @@ function scheduleTaskForRootDuringMicrotask( let schedulerPriorityLevel; switch (lanesToEventPriority(nextLanes)) { + // Scheduler does have an "ImmediatePriority", but now that we use + // microtasks for sync work we no longer use that. Any sync work that + // reaches this path is meant to be time sliced. case DiscreteEventPriority: - schedulerPriorityLevel = ImmediateSchedulerPriority; - break; case ContinuousEventPriority: schedulerPriorityLevel = UserBlockingSchedulerPriority; break; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 196859f6fa7ba..c40fc53704994 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -765,11 +765,12 @@ export function scheduleUpdateOnFiber( // The incoming update might unblock the current render. Interrupt the // current attempt and restart from the top. prepareFreshStack(root, NoLanes); + const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } @@ -832,11 +833,12 @@ export function scheduleUpdateOnFiber( // effect of interrupting the current render and switching to the update. // TODO: Make sure this doesn't override pings that happen while we've // already started rendering. + const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } } @@ -898,100 +900,120 @@ export function performWorkOnRoot( // for too long ("expired" work, to prevent starvation), or we're in // sync-updates-by-default mode. const shouldTimeSlice = - !forceSync && - !includesBlockingLane(lanes) && - !includesExpiredLane(root, lanes); + (!forceSync && + !includesBlockingLane(lanes) && + !includesExpiredLane(root, lanes)) || + // If we're prerendering, then we should use the concurrent work loop + // even if the lanes are synchronous, so that prerendering never blocks + // the main thread. + // TODO: We should consider doing this whenever a sync lane is suspended, + // even for regular pings. + (enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes)); + let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); + : renderRootSync(root, lanes, true); - if (exitStatus !== RootInProgress) { + do { let renderWasConcurrent = shouldTimeSlice; - do { - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended( + if (exitStatus === RootInProgress) { + // Render phase is still in progress. + if ( + enableSiblingPrerendering && + workInProgressRootIsPrerendering && + !shouldTimeSlice + ) { + // We're in prerendering mode, but time slicing is not enabled. This + // happens when something suspends during a synchronous update. Exit the + // the work loop. When we resume, we'll use the concurrent work loop so + // that prerendering is non-blocking. + // + // Mark the root as suspended. Usually we do this at the end of the + // render phase, but we do it here so that we resume in + // prerendering mode. + // TODO: Consider always calling markRootSuspended immediately. + // Needs to be *after* we attach a ping listener, though. + const didAttemptEntireTree = false; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + } + break; + } else if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + } else { + // The render completed. + + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + const finishedWork: Fiber = (root.current.alternate: any); + if ( + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) + ) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes, false); + // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + renderWasConcurrent = false; + // Need to check the exit status again. + continue; + } + + // Check if something threw + if ( + (disableLegacyMode || root.tag !== LegacyRoot) && + exitStatus === RootErrored + ) { + const lanesThatJustErrored = lanes; + const errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, - lanes, - NoLane, - workInProgressRootDidSkipSuspendedSiblings, + lanesThatJustErrored, ); - } else { - // The render completed. - - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - const finishedWork: Fiber = (root.current.alternate: any); - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); - // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - renderWasConcurrent = false; - // Need to check the exit status again. - continue; - } - - // Check if something threw - if ( - (disableLegacyMode || root.tag !== LegacyRoot) && - exitStatus === RootErrored - ) { - const lanesThatJustErrored = lanes; - const errorRetryLanes = getLanesToRetrySynchronouslyOnError( + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( root, lanesThatJustErrored, + errorRetryLanes, ); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - lanesThatJustErrored, - errorRetryLanes, - ); - renderWasConcurrent = false; - // Need to check the exit status again. - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } else { - // The root errored yet again. Proceed to commit the tree. - } + renderWasConcurrent = false; + // Need to check the exit status again. + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; + } else { + // The root errored yet again. Proceed to commit the tree. } } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended( - root, - lanes, - NoLane, - workInProgressRootDidSkipSuspendedSiblings, - ); - break; - } - - // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. - finishConcurrentRender(root, exitStatus, finishedWork, lanes); } - break; - } while (true); - } + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + // Since this is a fatal error, we're going to pretend we attempted + // the entire tree, to avoid scheduling a prerender. + const didAttemptEntireTree = true; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + break; + } + + // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } + break; + } while (true); ensureRootIsScheduled(root); } @@ -1024,7 +1046,7 @@ function recoverFromConcurrentError( rootWorkInProgress.flags |= ForceClientRender; } - const exitStatus = renderRootSync(root, errorRetryLanes); + const exitStatus = renderRootSync(root, errorRetryLanes, false); if (exitStatus !== RootErrored) { // Successfully finished rendering on retry @@ -1108,11 +1130,13 @@ function finishConcurrentRender( // This is a transition, so we should exit without committing a // placeholder and without scheduling a timeout. Delay indefinitely // until we receive more data. + const didAttemptEntireTree = + !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); return; } @@ -1168,11 +1192,13 @@ function finishConcurrentRender( // Don't bother with a very short suspense time. if (msUntilTimeout > 10) { + const didAttemptEntireTree = + !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); const nextLanes = getNextLanes(root, NoLanes); @@ -1286,7 +1312,8 @@ function commitRootWhenReady( completedRenderEndTime, ), ); - markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings); + const didAttemptEntireTree = !didSkipSuspendedSiblings; + markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree); return; } } @@ -1409,7 +1436,7 @@ function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didSkipSuspendedSiblings: boolean, + didAttemptEntireTree: boolean, ) { // When suspending, we should always exclude lanes that were pinged or (more // rarely, since we try to avoid it) updated during the render phase. @@ -1418,12 +1445,7 @@ function markRootSuspended( suspendedLanes, workInProgressRootInterleavedUpdatedLanes, ); - _markRootSuspended( - root, - suspendedLanes, - spawnedLane, - didSkipSuspendedSiblings, - ); + _markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree); } export function flushRoot(root: FiberRoot, lanes: Lanes) { @@ -1965,7 +1987,12 @@ export function renderDidSuspendDelayIfPossible(): void { if ( !workInProgressRootDidSkipSuspendedSiblings && - !includesBlockingLane(workInProgressRootRenderLanes) + // Check if the root will be blocked from committing. + // TODO: Consider aligning this better with the rest of the logic. Maybe + // we should only set the exit status to RootSuspendedWithDelay if this + // condition is true? And remove the equivalent checks elsewhere. + (includesOnlyTransitions(workInProgressRootRenderLanes) || + getSuspenseHandler() === null) ) { // This render may not have originally been scheduled as a prerender, but // something suspended inside the visible part of the tree, which means we @@ -1991,11 +2018,12 @@ export function renderDidSuspendDelayIfPossible(): void { // pinged or updated while we were rendering. // TODO: Consider unwinding immediately, using the // SuspendedOnHydration mechanism. + const didAttemptEntireTree = false; markRootSuspended( workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } } @@ -2025,7 +2053,11 @@ export function renderHasNotSuspendedYet(): boolean { // TODO: Over time, this function and renderRootConcurrent have become more // and more similar. Not sure it makes sense to maintain forked paths. Consider // unifying them again. -function renderRootSync(root: FiberRoot, lanes: Lanes) { +function renderRootSync( + root: FiberRoot, + lanes: Lanes, + shouldYieldForPrerendering: boolean, +): RootExitStatus { const prevExecutionContext = executionContext; executionContext |= RenderContext; const prevDispatcher = pushDispatcher(root.containerInfo); @@ -2065,6 +2097,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { } let didSuspendInShell = false; + let exitStatus = workInProgressRootExitStatus; outer: do { try { if ( @@ -2086,16 +2119,37 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { // Selective hydration. An update flowed into a dehydrated tree. // Interrupt the current render so the work loop can switch to the // hydration lane. + // TODO: I think we might not need to reset the stack here; we can + // just yield and reset the stack when we re-enter the work loop, + // like normal. resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; + exitStatus = RootDidNotComplete; break outer; } case SuspendedOnImmediate: - case SuspendedOnData: { - if (!didSuspendInShell && getSuspenseHandler() === null) { + case SuspendedOnData: + case SuspendedOnDeprecatedThrowPromise: { + if (getSuspenseHandler() === null) { didSuspendInShell = true; } - // Intentional fallthrough + const reason = workInProgressSuspendedReason; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason); + if ( + enableSiblingPrerendering && + shouldYieldForPrerendering && + workInProgressRootIsPrerendering + ) { + // We've switched into prerendering mode. This implies that we + // suspended outside of a Suspense boundary, which means this + // render will be blocked from committing. Yield to the main + // thread so we can switch to prerendering using the concurrent + // work loop. + exitStatus = RootInProgress; + break outer; + } + break; } default: { // Unwind then continue with the normal work loop. @@ -2108,6 +2162,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { } } workLoopSync(); + exitStatus = workInProgressRootExitStatus; break; } catch (thrownValue) { handleThrow(root, thrownValue); @@ -2130,14 +2185,6 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { popDispatcher(prevDispatcher); popAsyncDispatcher(prevAsyncDispatcher); - if (workInProgress !== null) { - // This is a sync render, so we should have finished the whole tree. - throw new Error( - 'Cannot commit an incomplete root. This error is likely caused by a ' + - 'bug in React. Please file an issue.', - ); - } - if (__DEV__) { if (enableDebugTracing) { logRenderStopped(); @@ -2148,14 +2195,21 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { markRenderStopped(); } - // Set this to null to indicate there's no in-progress render. - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; + if (workInProgress !== null) { + // Did not complete the tree. This can happen if something suspended in + // the shell. + } else { + // Normal case. We completed the whole tree. + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; - // It's safe to process the queue now that the render phase is complete. - finishQueueingConcurrentUpdates(); + // It's safe to process the queue now that the render phase is complete. + finishQueueingConcurrentUpdates(); + } - return workInProgressRootExitStatus; + return exitStatus; } // The work loop is an extremely hot path. Tell Closure not to inline it. @@ -2201,9 +2255,7 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) { // // If we were previously in prerendering mode, check if we received any new // data during an interleaved event. - if (workInProgressRootIsPrerendering) { - workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); - } + workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); } if (__DEV__) { @@ -3753,6 +3805,9 @@ function pingSuspendedRoot( // the logic of whether or not a root suspends once it completes. // TODO: If we're rendering sync either due to Sync, Batched or expired, // we should probably never restart. + // TODO: Attach different listeners depending on whether the listener was + // attached during prerendering. Prerender pings should not interrupt + // normal renders. // If we're suspended with delay, or if it's a retry, we'll always suspend // so we can always restart. diff --git a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js index fd03ba7310f83..8ca142cb50517 100644 --- a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js +++ b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js @@ -420,6 +420,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); @@ -459,6 +463,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); @@ -533,6 +541,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); diff --git a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js index 37d907b0fdc65..235e8df2201de 100644 --- a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js @@ -479,4 +479,75 @@ describe('ReactSiblingPrerendering', () => { assertLog([]); }, ); + + it( + 'when a synchronous update suspends outside a boundary, the resulting' + + 'prerender is concurrent', + async () => { + function App() { + return ( + <> + + + + + + + ); + } + + const root = ReactNoop.createRoot(); + // Mount the root synchronously + ReactNoop.flushSync(() => root.render()); + + // Synchronously render everything until we suspend in the shell + assertLog(['A', 'B', 'Suspend! [Async]']); + + if (gate('enableSiblingPrerendering')) { + // The rest of the siblings begin to prerender concurrently. Notice + // that we don't unwind here; we pick up where we left off above. + await waitFor(['C']); + await waitFor(['D']); + } + + assertLog([]); + expect(root).toMatchRenderedOutput(null); + + await resolveText('Async'); + assertLog(['A', 'B', 'Async', 'C', 'D']); + expect(root).toMatchRenderedOutput('ABAsyncCD'); + }, + ); + + it('restart a suspended sync render if something suspends while prerendering the siblings', async () => { + function App() { + return ( + <> + + + + + + + ); + } + + const root = ReactNoop.createRoot(); + // Mount the root synchronously + ReactNoop.flushSync(() => root.render()); + + // Synchronously render everything until we suspend in the shell + assertLog(['A', 'B', 'Suspend! [Async]']); + + if (gate('enableSiblingPrerendering')) { + // The rest of the siblings begin to prerender concurrently + await waitFor(['C']); + } + + // While we're prerendering, Async resolves. We should unwind and + // start over, rather than continue prerendering D. + await resolveText('Async'); + assertLog(['A', 'B', 'Async', 'C', 'D']); + expect(root).toMatchRenderedOutput('ABAsyncCD'); + }); }); From be94b108264e30873d4b679771e07ce14491e413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 16 Oct 2024 10:57:08 -0400 Subject: [PATCH 284/426] [Flight] Enable sync stack traces for errors and console replay (#31270) This was gated behind `enableOwnerStacks` since they share some code paths but it's really part of `enableServerComponentLogs`. This just includes the server-side regular stack on Error/replayed logs but doesn't use console.createTask and doesn't include owner stacks. --- .../react-client/src/ReactFlightClient.js | 7 ++--- .../src/__tests__/ReactFlight-test.js | 29 +++++++++++++++++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 141058fb9dfb2..2a6165c932a16 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -46,6 +46,7 @@ import { enableRefAsProp, enableFlightReadableStream, enableOwnerStacks, + enableServerComponentLogs, } from 'shared/ReactFeatureFlags'; import { @@ -1928,7 +1929,7 @@ function resolveErrorDev( } let error; - if (!enableOwnerStacks) { + if (!enableOwnerStacks && !enableServerComponentLogs) { // Executing Error within a native stack isn't really limited to owner stacks // but we gate it behind the same flag for now while iterating. // eslint-disable-next-line react-internal/prod-error-codes @@ -2463,9 +2464,7 @@ function resolveConsoleEntry( const env = payload[3]; const args = payload.slice(4); - if (!enableOwnerStacks) { - // Printing with stack isn't really limited to owner stacks but - // we gate it behind the same flag for now while iterating. + if (!enableOwnerStacks && !enableServerComponentLogs) { bindToConsole(methodName, args, env)(); return; } diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 7e1017276c976..92efd84bf0d7a 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -1346,7 +1346,10 @@ describe('ReactFlight', () => { errors: [ { message: 'This is an error', - stack: gate(flags => flags.enableOwnerStacks) + stack: gate( + flags => + flags.enableOwnerStacks || flags.enableServerComponentLogs, + ) ? expect.stringContaining( 'Error: This is an error\n' + ' at eval (eval at testFunction (eval at createFakeFunction (**), :1:35)\n' + @@ -1378,7 +1381,17 @@ describe('ReactFlight', () => { ['file:///testing.js', 'Server'], [__filename, 'Server'], ] - : [], + : gate(flags => flags.enableServerComponentLogs) + ? [ + // TODO: What should we request here? The outer () or the inner (inspected-page.html)? + ['inspected-page.html:29:11), ', 'Server'], + [ + 'file://~/(some)(really)(exotic-directory)/ReactFlight-test.js', + 'Server', + ], + ['file:///testing.js', 'Server'], + ] + : [], }); } else { expect(errors.map(getErrorForJestMatcher)).toEqual([ @@ -2940,7 +2953,11 @@ describe('ReactFlight', () => { .join('\n') .replaceAll( ' (/', - gate(flags => flags.enableOwnerStacks) ? ' (file:///' : ' (/', + gate( + flags => flags.enableOwnerStacks || flags.enableServerComponentLogs, + ) + ? ' (file:///' + : ' (/', ); // The eval will end up normalizing these let sawReactPrefix = false; @@ -2974,6 +2991,12 @@ describe('ReactFlight', () => { 'third-party', 'third-party', ]); + } else if (__DEV__ && gate(flags => flags.enableServerComponentLogs)) { + expect(environments.slice(0, 3)).toEqual([ + 'third-party', + 'third-party', + 'third-party', + ]); } else { expect(environments).toEqual([]); } From 77b637d61200eef4dca4cbe4258da358d6337c7b Mon Sep 17 00:00:00 2001 From: Edmond Chui <1967998+EdmondChuiHW@users.noreply.github.com> Date: Wed, 16 Oct 2024 16:45:24 +0100 Subject: [PATCH 285/426] Add Bridge types for Fusebox (#31274) New types used by Fusebox https://github.com/facebookexperimental/rn-chrome-devtools-frontend/pull/117 --- packages/react-devtools-fusebox/src/frontend.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-fusebox/src/frontend.d.ts b/packages/react-devtools-fusebox/src/frontend.d.ts index 74a88c36a85f8..52536739ccaa1 100644 --- a/packages/react-devtools-fusebox/src/frontend.d.ts +++ b/packages/react-devtools-fusebox/src/frontend.d.ts @@ -15,7 +15,9 @@ export type Wall = { }; export type Bridge = { - shutdown: () => void, + addListener(event: string, listener: (params: unknown) => any): void; + removeListener(event: string, listener: Function): void; + shutdown: () => void; }; export type Store = Object; export type BrowserTheme = 'dark' | 'light'; From a3d9ea05bf01f3c3d7aedc2d938c581ad11fd14a Mon Sep 17 00:00:00 2001 From: Timothy Yung Date: Wed, 16 Oct 2024 11:19:01 -0700 Subject: [PATCH 286/426] Delete `__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED` from React Native Renderer (#31276) ## Summary The React Native Renderer exports a `__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED` property with a single method that has no remaining call sites: `computeComponentStackForErrorReporting` This PR cleans up this unused export. ## How did you test this change? ``` $ yarn $ yarn flow fabric $ yarn test ``` --- .../src/ReactNativeRenderer.js | 15 ----- .../src/ReactNativeTypes.js | 8 --- .../ReactNativeError-test.internal.js | 56 ------------------- 3 files changed, 79 deletions(-) diff --git a/packages/react-native-renderer/src/ReactNativeRenderer.js b/packages/react-native-renderer/src/ReactNativeRenderer.js index 4ec5ab2c58529..7f959184c95ef 100644 --- a/packages/react-native-renderer/src/ReactNativeRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeRenderer.js @@ -26,7 +26,6 @@ import { defaultOnRecoverableError, } from 'react-reconciler/src/ReactFiberReconciler'; // TODO: direct imports like some-package/src/* are bad. Fix me. -import {getStackByFiberInDevAndProd} from 'react-reconciler/src/ReactFiberComponentStack'; import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal'; import { setBatchingImplementation, @@ -35,7 +34,6 @@ import { // Modules provided by RN: import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; -import {getClosestInstanceFromNode} from './ReactNativeComponentTree'; import {getInspectorDataForInstance} from './ReactNativeFiberInspector'; import {LegacyRoot} from 'react-reconciler/src/ReactRootTags'; import { @@ -194,20 +192,8 @@ function createPortal( setBatchingImplementation(batchedUpdatesImpl, discreteUpdates); -function computeComponentStackForErrorReporting(reactTag: number): string { - const fiber = getClosestInstanceFromNode(reactTag); - if (!fiber) { - return ''; - } - return getStackByFiberInDevAndProd(fiber); -} - const roots = new Map(); -const Internals = { - computeComponentStackForErrorReporting, -}; - export { // This is needed for implementation details of TouchableNativeFeedback // Remove this once TouchableNativeFeedback doesn't use cloneElement @@ -220,7 +206,6 @@ export { unmountComponentAtNodeAndRemoveContainer, createPortal, batchedUpdates as unstable_batchedUpdates, - Internals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, // This export is typically undefined in production builds. // See the "enableGetInspectorDataForInstanceInProduction" flag. getInspectorDataForInstance, diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 03c03cfba0072..540ac1cf2aa70 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -139,13 +139,6 @@ declare const ensureNativeMethodsAreSynced: NativeMethods; export type HostInstance = NativeMethods; export type HostComponent = AbstractComponent; -type SecretInternalsType = { - computeComponentStackForErrorReporting(tag: number): string, - // TODO (bvaughn) Decide which additional types to expose here? - // And how much information to fill in for the above types. - ... -}; - type InspectorDataProps = $ReadOnly<{ [propName: string]: string, ... @@ -233,7 +226,6 @@ export type ReactNativeType = { unmountComponentAtNode(containerTag: number): void, unmountComponentAtNodeAndRemoveContainer(containerTag: number): void, +unstable_batchedUpdates: (fn: (T) => void, bookkeeping: T) => void, - +__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType, ... }; diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js index a7ac05b214492..8eb6421d49250 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeError-test.internal.js @@ -10,32 +10,15 @@ 'use strict'; -let React; -let ReactNative; let createReactNativeComponentClass; -let computeComponentStackForErrorReporting; - -function normalizeCodeLocInfo(str) { - return ( - str && - str.replace(/\n +(?:at|in) ([\S]+)[^\n]*/g, function (m, name) { - return '\n in ' + name + ' (at **)'; - }) - ); -} describe('ReactNativeError', () => { beforeEach(() => { jest.resetModules(); - React = require('react'); - ReactNative = require('react-native-renderer'); createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') .ReactNativeViewConfigRegistry.register; - computeComponentStackForErrorReporting = - ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED - .computeComponentStackForErrorReporting; }); it('should throw error if null component registration getter is used', () => { @@ -49,43 +32,4 @@ describe('ReactNativeError', () => { 'View config getter callback for component `View` must be a function (received `null`)', ); }); - - // @gate !disableLegacyMode - it('should be able to extract a component stack from a native view', () => { - const View = createReactNativeComponentClass('View', () => ({ - validAttributes: {foo: true}, - uiViewClassName: 'View', - })); - - const ref = React.createRef(); - - function FunctionComponent(props) { - return props.children; - } - - class ClassComponent extends React.Component { - render() { - return ( - - - - ); - } - } - - ReactNative.render(, 1); - - const reactTag = ReactNative.findNodeHandle(ref.current); - - const componentStack = normalizeCodeLocInfo( - computeComponentStackForErrorReporting(reactTag), - ); - - expect(componentStack).toBe( - '\n' + - ' in View (at **)\n' + - ' in FunctionComponent (at **)\n' + - ' in ClassComponent (at **)', - ); - }); }); From 3ed64f8232d0709f93f096c6fb9f7a16865b0ff5 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 16 Oct 2024 18:44:50 -0400 Subject: [PATCH 287/426] [ez] Update references to 'forget' in react-compiler-runtime (#31277) Updates the runtime to reference React Compiler instead of Forget. --- .../react-compiler-runtime/src/index.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/packages/react-compiler-runtime/src/index.ts b/compiler/packages/react-compiler-runtime/src/index.ts index 7b8cbe36f52db..57f61f3e8c017 100644 --- a/compiler/packages/react-compiler-runtime/src/index.ts +++ b/compiler/packages/react-compiler-runtime/src/index.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -'use no forget'; +'use no memo'; import * as React from 'react'; @@ -67,7 +67,7 @@ const LazyGuardDispatcher: {[key: string]: (...args: Array) => any} = {}; ].forEach(name => { LazyGuardDispatcher[name] = () => { throw new Error( - `[React] Unexpected React hook call (${name}) from a React Forget compiled function. ` + + `[React] Unexpected React hook call (${name}) from a React compiled function. ` + "Check that all hooks are called directly and named according to convention ('use[A-Z]') ", ); }; @@ -79,7 +79,7 @@ let originalDispatcher: unknown = null; LazyGuardDispatcher['useMemoCache'] = (count: number) => { if (originalDispatcher == null) { throw new Error( - 'React Forget internal invariant violation: unexpected null dispatcher', + 'React Compiler internal invariant violation: unexpected null dispatcher', ); } else { return (originalDispatcher as any).useMemoCache(count); @@ -103,12 +103,12 @@ const guardFrames: Array = []; /** * When `enableEmitHookGuards` is set, this does runtime validation * of the no-conditional-hook-calls rule. - * As Forget needs to statically understand which calls to move out of - * conditional branches (i.e. Forget cannot memoize the results of hook + * As React Compiler needs to statically understand which calls to move out of + * conditional branches (i.e. React Compiler cannot memoize the results of hook * calls), its understanding of "the rules of React" are more restrictive. * This validation throws on unsound inputs at runtime. * - * Components should only be invoked through React as Forget could memoize + * Components should only be invoked through React as React Compiler could memoize * the call to AnotherComponent, introducing conditional hook calls in its * compiled output. * ```js @@ -148,7 +148,7 @@ export function $dispatcherGuard(kind: GuardKind) { if (curr === LazyGuardDispatcher) { throw new Error( - `[React] Unexpected call to custom hook or component from a React Forget compiled function. ` + + `[React] Unexpected call to custom hook or component from a React compiled function. ` + "Check that (1) all hooks are called directly and named according to convention ('use[A-Z]') " + 'and (2) components are returned as JSX instead of being directly invoked.', ); @@ -160,7 +160,7 @@ export function $dispatcherGuard(kind: GuardKind) { if (lastFrame == null) { throw new Error( - 'React Forget internal error: unexpected null in guard stack', + 'React Compiler internal error: unexpected null in guard stack', ); } if (guardFrames.length === 0) { @@ -176,12 +176,12 @@ export function $dispatcherGuard(kind: GuardKind) { const lastFrame = guardFrames.pop(); if (lastFrame == null) { throw new Error( - 'React Forget internal error: unexpected null in guard stack', + 'React Compiler internal error: unexpected null in guard stack', ); } setCurrent(lastFrame); } else { - throw new Error('Forget internal error: unreachable block' + kind); + throw new Error('React Compiler internal error: unreachable block' + kind); } } From bf7e210cb5672685bfe992a3b253880f5a3d47f5 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 17 Oct 2024 09:02:41 +0100 Subject: [PATCH 288/426] tests[react-devtools]: added tests for Compiler integration (#31241) Adds tests for Compiler integration. This includes: - Tests against Compiler from source. - Versioned (18.2 - <19) tests against Compiler from npm. For tests against React 18.2, I had to download `react-compiler-runtime` from npm and put it to `react/compiler-runtime.js`. --- .../workflows/devtools_regression_tests.yml | 1 + .../__tests__/compiler-integration-test.js | 101 ++++++++++++++++++ .../ci/download_devtools_regression_build.js | 19 +++- 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 packages/react-devtools-shared/src/__tests__/compiler-integration-test.js diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml index be4c38e25612b..213f58218cc2b 100644 --- a/.github/workflows/devtools_regression_tests.yml +++ b/.github/workflows/devtools_regression_tests.yml @@ -103,6 +103,7 @@ jobs: - "16.8" # hooks - "17.0" - "18.0" + - "18.2" # compiler polyfill continue-on-error: true steps: - uses: actions/checkout@v4 diff --git a/packages/react-devtools-shared/src/__tests__/compiler-integration-test.js b/packages/react-devtools-shared/src/__tests__/compiler-integration-test.js new file mode 100644 index 0000000000000..25bbf59488ffd --- /dev/null +++ b/packages/react-devtools-shared/src/__tests__/compiler-integration-test.js @@ -0,0 +1,101 @@ +/** + * 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 {getVersionedRenderImplementation} from './utils'; + +describe('CompilerIntegration', () => { + global.IS_REACT_ACT_ENVIRONMENT = true; + let React; + let act; + let useMemoCache; + + beforeEach(() => { + React = require('react'); + require('react-dom'); + require('react-dom/client'); + useMemoCache = require('react/compiler-runtime').c; + + const utils = require('./utils'); + act = utils.act; + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + const {render} = getVersionedRenderImplementation(); + + // @reactVersion >= 18.2 + it('By default, component display names should not have Forget prefix', () => { + const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__; + const reactDOMFiberRendererInterface = hook.rendererInterfaces.get(1); + expect(reactDOMFiberRendererInterface).not.toBeFalsy(); + + const Foo = () => { + // eslint-disable-next-line no-unused-vars + const [val, setVal] = React.useState(null); + + return ( +
+ +
+ ); + }; + const Bar = () =>
Hi!
; + + act(() => render()); + + expect( + reactDOMFiberRendererInterface + .getDisplayNameForElementID(2) + .indexOf('Forget'), + ).toBe(-1); + expect( + reactDOMFiberRendererInterface + .getDisplayNameForElementID(3) + .indexOf('Forget'), + ).toBe(-1); + }); + + // For React 18.2, this will install uMC polyfill from react-compiler-runtime available on npm. + // @reactVersion >= 18.2 + it('If useMemoCache used, the corresponding displayName for a component should have Forget prefix', () => { + const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__; + const reactDOMFiberRendererInterface = hook.rendererInterfaces.get(1); + expect(reactDOMFiberRendererInterface).not.toBeFalsy(); + + const Foo = () => { + // eslint-disable-next-line no-unused-vars + const $ = useMemoCache(1); + // eslint-disable-next-line no-unused-vars + const [val, setVal] = React.useState(null); + + return ( +
+ +
+ ); + }; + const Bar = () =>
Hi!
; + + act(() => render()); + + // useMemoCache is only used by Foo component + expect( + reactDOMFiberRendererInterface + .getDisplayNameForElementID(2) + .indexOf('Forget'), + ).toBe(0); + expect( + reactDOMFiberRendererInterface + .getDisplayNameForElementID(3) + .indexOf('Forget'), + ).toBe(-1); + }); +}); diff --git a/scripts/ci/download_devtools_regression_build.js b/scripts/ci/download_devtools_regression_build.js index 01ef377094cc0..7195c194927b9 100755 --- a/scripts/ci/download_devtools_regression_build.js +++ b/scripts/ci/download_devtools_regression_build.js @@ -82,11 +82,12 @@ async function downloadRegressionBuild() { ); await exec(`mv ${movePackageString} ${buildPath}`); + const reactVersion = semver.coerce(version).version; // For React versions earlier than 18.0.0, we explicitly scheduler v0.20.1, which // is the first version that has unstable_mock, which DevTools tests need, but also // has Scheduler.unstable_trace, which, although we don't use in DevTools tests // is imported by older React versions and will break if it's not there - if (semver.lte(semver.coerce(version).version, '18.0.0')) { + if (semver.lte(reactVersion, '18.0.0')) { await exec(`npm install --prefix ${REGRESSION_FOLDER} scheduler@0.20.1`); } @@ -108,6 +109,22 @@ async function downloadRegressionBuild() { )} ${buildPath}` ); } + + if (semver.gte(reactVersion, '18.2.0') && semver.lt(reactVersion, '19')) { + console.log(chalk.white(`Downloading react-compiler-runtime\n`)); + await exec( + `npm install --prefix ${REGRESSION_FOLDER} react-compiler-runtime` + ); + + console.log( + chalk.white( + `Moving react-compiler-runtime to react/compiler-runtime.js\n` + ) + ); + await exec( + `mv ${REGRESSION_FOLDER}/node_modules/react-compiler-runtime/dist/index.js ${buildPath}/react/compiler-runtime.js` + ); + } } async function main() { From c91b3b090ad406fcd103483de0abb6adf44b6f48 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Thu, 17 Oct 2024 18:15:32 +0100 Subject: [PATCH 289/426] JSX Outlining (#30956) Currently, the react compiler can not compile within callbacks which can potentially cause over rendering. Consider this example: ```jsx function Component(countries, onDelete) { const name = useFoo(); return countries.map(() => { return ( ); }); } ``` In this case, there's no memoization of the nested jsx elements. But instead if we were to manually refactor the nested jsx into separate component like this: ```jsx function Component(countries, onDelete) { const name = useFoo(); return countries.map(() => { return ; }); } function Temp({ name, onDelete }) { return ( ); } ``` The compiler can now optimise both these components: ```jsx function Component(countries, onDelete) { const $ = _c(4); const name = useFoo(); let t0; if ($[0] !== name || $[1] !== onDelete || $[2] !== countries) { t0 = countries.map(() => ); $[0] = name; $[1] = onDelete; $[2] = countries; $[3] = t0; } else { t0 = $[3]; } return t0; } function Temp(t0) { const $ = _c(7); const { name, onDelete } = t0; let t1; if ($[0] !== name) { t1 = ; $[0] = name; $[1] = t1; } else { t1 = $[1]; } let t2; if ($[2] !== onDelete) { t2 = ; $[2] = onDelete; $[3] = t2; } else { t2 = $[3]; } let t3; if ($[4] !== t1 || $[5] !== t2) { t3 = ( {t1} {t2} ); $[4] = t1; $[5] = t2; $[6] = t3; } else { t3 = $[6]; } return t3; } ``` Now, when `countries` is updated by adding one single value, only the newly added value is re-rendered and not the entire list. Rather than having to do this manually, this PR teaches the react compiler to do this transformation. This PR adds a new pass (`OutlineJsx`) to capture nested jsx statements and outline them in a separate component. This newly outlined component can then by memoized by the compiler, giving us more fine grained rendering. --- .../src/Entrypoint/Pipeline.ts | 5 + .../src/Entrypoint/Program.ts | 17 +- .../src/HIR/Environment.ts | 48 ++ .../src/HIR/HIR.ts | 20 +- .../src/Optimization/OutlineJsx.ts | 466 ++++++++++++++++++ ...jsx-outlining-child-stored-in-id.expect.md | 143 ++++++ .../jsx-outlining-child-stored-in-id.js | 40 ++ .../jsx-outlining-jsx-stored-in-id.expect.md | 145 ++++++ .../jsx-outlining-jsx-stored-in-id.js | 38 ++ .../jsx-outlining-separate-nested.expect.md | 186 +++++++ .../compiler/jsx-outlining-separate-nested.js | 46 ++ .../compiler/jsx-outlining-simple.expect.md | 142 ++++++ .../fixtures/compiler/jsx-outlining-simple.js | 36 ++ .../todo.jsx-outlining-children.expect.md | 121 +++++ .../compiler/todo.jsx-outlining-children.js | 36 ++ ...odo.jsx-outlining-duplicate-prop.expect.md | 132 +++++ .../todo.jsx-outlining-duplicate-prop.js | 41 ++ 17 files changed, 1641 insertions(+), 21 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 900e4f4908494..7ae520a144c9b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -103,6 +103,7 @@ import {lowerContextAccess} from '../Optimization/LowerContextAccess'; import {validateNoSetStateInPassiveEffects} from '../Validation/ValidateNoSetStateInPassiveEffects'; import {validateNoJSXInTryStatement} from '../Validation/ValidateNoJSXInTryStatement'; import {propagateScopeDependenciesHIR} from '../HIR/PropagateScopeDependenciesHIR'; +import {outlineJSX} from '../Optimization/OutlineJsx'; export type CompilerPipelineValue = | {kind: 'ast'; name: string; value: CodegenFunction} @@ -278,6 +279,10 @@ function* runWithEnvironment( value: hir, }); + if (env.config.enableJsxOutlining) { + outlineJSX(hir); + } + if (env.config.enableFunctionOutlining) { outlineFunctions(hir, fbtOperands); yield log({kind: 'hir', name: 'OutlineFunctions', value: hir}); diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts index d60f86e7fa4e2..1b1a82db0b908 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts @@ -199,7 +199,7 @@ function insertNewOutlinedFunctionNode( program: NodePath, originalFn: BabelFn, compiledFn: CodegenFunction, -): NodePath { +): BabelFn { switch (originalFn.type) { case 'FunctionDeclaration': { return originalFn.insertAfter( @@ -491,18 +491,11 @@ export function compileProgram( fn.skip(); ALREADY_COMPILED.add(fn.node); if (outlined.type !== null) { - CompilerError.throwTodo({ - reason: `Implement support for outlining React functions (components/hooks)`, - loc: outlined.fn.loc, + queue.push({ + kind: 'outlined', + fn, + fnType: outlined.type, }); - /* - * Above should be as simple as the following, but needs testing: - * queue.push({ - * kind: "outlined", - * fn, - * fnType: outlined.type, - * }); - */ } } compiledFns.push({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index b7d2b645c5b53..b85d9425cb7ac 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -354,6 +354,54 @@ const EnvironmentConfigSchema = z.object({ */ enableFunctionOutlining: z.boolean().default(true), + /** + * If enabled, this will outline nested JSX into a separate component. + * + * This will enable the compiler to memoize the separate component, giving us + * the same behavior as compiling _within_ the callback. + * + * ``` + * function Component(countries, onDelete) { + * const name = useFoo(); + * return countries.map(() => { + * return ( + * + * {name} + * + * + * ); + * }); + * } + * ``` + * + * will be transpiled to: + * + * ``` + * function Component(countries, onDelete) { + * const name = useFoo(); + * return countries.map(() => { + * return ( + * + * ); + * }); + * } + * + * function Temp({name, onDelete}) { + * return ( + * + * {name} + * + * + * ); + * } + * + * Both, `Component` and `Temp` will then be memoized by the compiler. + * + * With this change, when `countries` is updated by adding one single value, + * only the newly added value is re-rendered and not the entire list. + */ + enableJsxOutlining: z.boolean().default(false), + /* * Enables instrumentation codegen. This emits a dev-mode only call to an * instrumentation function, for components and hooks that Forget compiles. diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index e771b386b3942..263ec4c20877d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -920,15 +920,7 @@ export type InstructionValue = type: Type; loc: SourceLocation; } - | { - kind: 'JsxExpression'; - tag: Place | BuiltinTag; - props: Array; - children: Array | null; // null === no children - loc: SourceLocation; - openingLoc: SourceLocation; - closingLoc: SourceLocation; - } + | JsxExpression | { kind: 'ObjectExpression'; properties: Array; @@ -1074,6 +1066,16 @@ export type InstructionValue = loc: SourceLocation; }; +export type JsxExpression = { + kind: 'JsxExpression'; + tag: Place | BuiltinTag; + props: Array; + children: Array | null; // null === no children + loc: SourceLocation; + openingLoc: SourceLocation; + closingLoc: SourceLocation; +}; + export type JsxAttribute = | {kind: 'JsxSpreadAttribute'; argument: Place} | {kind: 'JsxAttribute'; name: string; place: Place}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts new file mode 100644 index 0000000000000..f10f97c425dd0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts @@ -0,0 +1,466 @@ +/** + * 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 invariant from 'invariant'; +import {Environment} from '../HIR'; +import { + BasicBlock, + GeneratedSource, + HIRFunction, + IdentifierId, + Instruction, + InstructionId, + InstructionKind, + JsxAttribute, + JsxExpression, + LoadGlobal, + makeBlockId, + makeIdentifierName, + makeInstructionId, + makeType, + ObjectProperty, + Place, + promoteTemporary, + promoteTemporaryJsxTag, +} from '../HIR/HIR'; +import {createTemporaryPlace} from '../HIR/HIRBuilder'; +import {printIdentifier} from '../HIR/PrintHIR'; +import {deadCodeElimination} from './DeadCodeElimination'; +import {assertExhaustive} from '../Utils/utils'; + +export function outlineJSX(fn: HIRFunction): void { + const outlinedFns: Array = []; + outlineJsxImpl(fn, outlinedFns); + + for (const outlinedFn of outlinedFns) { + fn.env.outlineFunction(outlinedFn, 'Component'); + } +} + +type JsxInstruction = Instruction & {value: JsxExpression}; +type LoadGlobalInstruction = Instruction & {value: LoadGlobal}; +type LoadGlobalMap = Map; + +type State = { + jsx: Array; + children: Set; +}; + +function outlineJsxImpl( + fn: HIRFunction, + outlinedFns: Array, +): void { + const globals: LoadGlobalMap = new Map(); + + function processAndOutlineJSX( + state: State, + rewriteInstr: Map>, + ): void { + if (state.jsx.length <= 1) { + return; + } + const result = process( + fn, + [...state.jsx].sort((a, b) => a.id - b.id), + globals, + ); + if (result) { + outlinedFns.push(result.fn); + rewriteInstr.set(state.jsx.at(0)!.id, result.instrs); + } + } + + for (const [, block] of fn.body.blocks) { + const rewriteInstr = new Map(); + let state: State = { + jsx: [], + children: new Set(), + }; + + for (let i = block.instructions.length - 1; i >= 0; i--) { + const instr = block.instructions[i]; + const {value, lvalue} = instr; + switch (value.kind) { + case 'LoadGlobal': { + globals.set(lvalue.identifier.id, instr as LoadGlobalInstruction); + break; + } + case 'FunctionExpression': { + outlineJsxImpl(value.loweredFunc.func, outlinedFns); + break; + } + + case 'JsxExpression': { + if (!state.children.has(lvalue.identifier.id)) { + processAndOutlineJSX(state, rewriteInstr); + + state = { + jsx: [], + children: new Set(), + }; + } + state.jsx.push(instr as JsxInstruction); + if (value.children) { + for (const child of value.children) { + state.children.add(child.identifier.id); + } + } + break; + } + case 'ArrayExpression': + case 'Await': + case 'BinaryExpression': + case 'CallExpression': + case 'ComputedDelete': + case 'ComputedLoad': + case 'ComputedStore': + case 'Debugger': + case 'DeclareContext': + case 'DeclareLocal': + case 'Destructure': + case 'FinishMemoize': + case 'GetIterator': + case 'IteratorNext': + case 'JSXText': + case 'JsxFragment': + case 'LoadContext': + case 'LoadLocal': + case 'MetaProperty': + case 'MethodCall': + case 'NewExpression': + case 'NextPropertyOf': + case 'ObjectExpression': + case 'ObjectMethod': + case 'PostfixUpdate': + case 'PrefixUpdate': + case 'Primitive': + case 'PropertyDelete': + case 'PropertyLoad': + case 'PropertyStore': + case 'RegExpLiteral': + case 'StartMemoize': + case 'StoreContext': + case 'StoreGlobal': + case 'StoreLocal': + case 'TaggedTemplateExpression': + case 'TemplateLiteral': + case 'TypeCastExpression': + case 'UnsupportedNode': + case 'UnaryExpression': { + break; + } + default: { + assertExhaustive(value, `Unexpected instruction: ${value}`); + } + } + } + processAndOutlineJSX(state, rewriteInstr); + + if (rewriteInstr.size > 0) { + const newInstrs = []; + for (let i = 0; i < block.instructions.length; i++) { + // InstructionId's are one-indexed, so add one to account for them. + const id = i + 1; + if (rewriteInstr.has(id)) { + const instrs = rewriteInstr.get(id); + newInstrs.push(...instrs); + } else { + newInstrs.push(block.instructions[i]); + } + } + block.instructions = newInstrs; + } + deadCodeElimination(fn); + } +} + +type OutlinedResult = { + instrs: Array; + fn: HIRFunction; +}; + +function process( + fn: HIRFunction, + jsx: Array, + globals: LoadGlobalMap, +): OutlinedResult | null { + /** + * In the future, add a check for backedge to outline jsx inside loops in a + * top level component. For now, only outline jsx in callbacks. + */ + if (fn.fnType === 'Component') { + return null; + } + + const props = collectProps(jsx); + if (!props) return null; + + const outlinedTag = fn.env.generateGloballyUniqueIdentifierName(null).value; + const newInstrs = emitOutlinedJsx(fn.env, jsx, props, outlinedTag); + if (!newInstrs) return null; + + const outlinedFn = emitOutlinedFn(fn.env, jsx, props, globals); + if (!outlinedFn) return null; + outlinedFn.id = outlinedTag; + + return {instrs: newInstrs, fn: outlinedFn}; +} + +function collectProps( + instructions: Array, +): Array | null { + const attributes: Array = []; + const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id)); + const seen: Set = new Set(); + for (const instr of instructions) { + const {value} = instr; + + for (const at of value.props) { + if (at.kind === 'JsxSpreadAttribute') { + return null; + } + + /* + * TODO(gsn): Handle attributes that have same value across + * the outlined jsx instructions. + */ + if (seen.has(at.name)) { + return null; + } + + if (at.kind === 'JsxAttribute') { + seen.add(at.name); + attributes.push(at); + } + } + + // TODO(gsn): Add support for children that are not jsx expressions + if ( + value.children && + value.children.some(child => !jsxIds.has(child.identifier.id)) + ) { + return null; + } + } + return attributes; +} + +function emitOutlinedJsx( + env: Environment, + instructions: Array, + props: Array, + outlinedTag: string, +): Array { + const loadJsx: Instruction = { + id: makeInstructionId(0), + loc: GeneratedSource, + lvalue: createTemporaryPlace(env, GeneratedSource), + value: { + kind: 'LoadGlobal', + binding: { + kind: 'ModuleLocal', + name: outlinedTag, + }, + loc: GeneratedSource, + }, + }; + promoteTemporaryJsxTag(loadJsx.lvalue.identifier); + const jsxExpr: Instruction = { + id: makeInstructionId(0), + loc: GeneratedSource, + lvalue: instructions.at(-1)!.lvalue, + value: { + kind: 'JsxExpression', + tag: {...loadJsx.lvalue}, + props, + children: null, + loc: GeneratedSource, + openingLoc: GeneratedSource, + closingLoc: GeneratedSource, + }, + }; + + return [loadJsx, jsxExpr]; +} + +function emitOutlinedFn( + env: Environment, + jsx: Array, + oldProps: Array, + globals: LoadGlobalMap, +): HIRFunction | null { + const instructions: Array = []; + const oldToNewProps = createOldToNewPropsMapping(env, oldProps); + + const propsObj: Place = createTemporaryPlace(env, GeneratedSource); + promoteTemporary(propsObj.identifier); + + const destructurePropsInstr = emitDestructureProps(env, propsObj, [ + ...oldToNewProps.values(), + ]); + instructions.push(destructurePropsInstr); + + const updatedJsxInstructions = emitUpdatedJsx(jsx, oldToNewProps); + const loadGlobalInstrs = emitLoadGlobals(jsx, globals); + if (!loadGlobalInstrs) { + return null; + } + instructions.push(...loadGlobalInstrs); + instructions.push(...updatedJsxInstructions); + + const block: BasicBlock = { + kind: 'block', + id: makeBlockId(0), + instructions, + terminal: { + id: makeInstructionId(0), + kind: 'return', + loc: GeneratedSource, + value: instructions.at(-1)!.lvalue, + }, + preds: new Set(), + phis: new Set(), + }; + + const fn: HIRFunction = { + loc: GeneratedSource, + id: null, + fnType: 'Other', + env, + params: [propsObj], + returnTypeAnnotation: null, + returnType: makeType(), + context: [], + effects: null, + body: { + entry: block.id, + blocks: new Map([[block.id, block]]), + }, + generator: false, + async: false, + directives: [], + }; + return fn; +} + +function emitLoadGlobals( + jsx: Array, + globals: LoadGlobalMap, +): Array | null { + const instructions: Array = []; + for (const {value} of jsx) { + // Add load globals instructions for jsx tags + if (value.tag.kind === 'Identifier') { + const loadGlobalInstr = globals.get(value.tag.identifier.id); + if (!loadGlobalInstr) { + return null; + } + instructions.push(loadGlobalInstr); + } + } + + return instructions; +} + +function emitUpdatedJsx( + jsx: Array, + oldToNewProps: Map, +): Array { + const newInstrs: Array = []; + + for (const instr of jsx) { + const {value} = instr; + const newProps: Array = []; + // Update old props references to use the newly destructured props param + for (const prop of value.props) { + invariant( + prop.kind === 'JsxAttribute', + `Expected only attributes but found ${prop.kind}`, + ); + if (prop.name === 'key') { + continue; + } + const newProp = oldToNewProps.get(prop.place.identifier.id); + invariant( + newProp !== undefined, + `Expected a new property for ${printIdentifier(prop.place.identifier)}`, + ); + newProps.push({ + ...prop, + place: newProp.place, + }); + } + + newInstrs.push({ + ...instr, + value: { + ...value, + props: newProps, + }, + }); + } + + return newInstrs; +} + +function createOldToNewPropsMapping( + env: Environment, + oldProps: Array, +): Map { + const oldToNewProps = new Map(); + + for (const oldProp of oldProps) { + invariant( + oldProp.kind === 'JsxAttribute', + `Expected only attributes but found ${oldProp.kind}`, + ); + + // Do not read key prop in the outlined component + if (oldProp.name === 'key') { + continue; + } + + const newProp: ObjectProperty = { + kind: 'ObjectProperty', + key: { + kind: 'string', + name: oldProp.name, + }, + type: 'property', + place: createTemporaryPlace(env, GeneratedSource), + }; + newProp.place.identifier.name = makeIdentifierName(oldProp.name); + oldToNewProps.set(oldProp.place.identifier.id, newProp); + } + + return oldToNewProps; +} + +function emitDestructureProps( + env: Environment, + propsObj: Place, + properties: Array, +): Instruction { + const destructurePropsInstr: Instruction = { + id: makeInstructionId(0), + lvalue: createTemporaryPlace(env, GeneratedSource), + loc: GeneratedSource, + value: { + kind: 'Destructure', + lvalue: { + pattern: { + kind: 'ObjectPattern', + properties, + }, + kind: InstructionKind.Let, + }, + loc: GeneratedSource, + value: propsObj, + }, + }; + return destructurePropsInstr; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md new file mode 100644 index 0000000000000..fd7ca41bcffa3 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md @@ -0,0 +1,143 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component(arr) { + const x = useX(); + return arr.map(i => { + <> + {arr.map((i, id) => { + let child = ( + + + + ); + + let jsx =
{child}
; + return jsx; + })} + ; + }); +} + +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return <>{i}; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(arr) { + const $ = _c(3); + const x = useX(); + let t0; + if ($[0] !== arr || $[1] !== x) { + t0 = arr.map((i) => { + arr.map((i_0, id) => { + const T0 = _temp; + const child = ; + + const jsx =
{child}
; + return jsx; + }); + }); + $[0] = arr; + $[1] = x; + $[2] = t0; + } else { + t0 = $[2]; + } + return t0; +} +function _temp(t0) { + const $ = _c(5); + const { i: i, x: x } = t0; + let t1; + if ($[0] !== i) { + t1 = ; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== x || $[3] !== t1) { + t2 = {t1}; + $[2] = x; + $[3] = t1; + $[4] = t2; + } else { + t2 = $[4]; + } + return t2; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== x || $[1] !== children) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = x; + $[1] = children; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const $ = _c(2); + const { i } = t0; + let t1; + if ($[0] !== i) { + t1 = <>{i}; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: exception) arr.map is not a function \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.js new file mode 100644 index 0000000000000..b7a82cd2a4be2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.js @@ -0,0 +1,40 @@ +// @enableJsxOutlining +function Component(arr) { + const x = useX(); + return arr.map(i => { + <> + {arr.map((i, id) => { + let child = ( + + + + ); + + let jsx =
{child}
; + return jsx; + })} + ; + }); +} + +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return <>{i}; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md new file mode 100644 index 0000000000000..496282e1ef611 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md @@ -0,0 +1,145 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + let jsx = ( + + + + ); + return jsx; + })} + + ); +} + +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== x || $[1] !== arr) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => { + const T0 = _temp; + const jsx = ; + return jsx; + }; + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = x; + $[1] = arr; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +function _temp(t0) { + const $ = _c(5); + const { i: i, x: x } = t0; + let t1; + if ($[0] !== i) { + t1 = ; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== x || $[3] !== t1) { + t2 = {t1}; + $[2] = x; + $[3] = t1; + $[4] = t2; + } else { + t2 = $[4]; + } + return t2; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== x || $[1] !== children) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = x; + $[1] = children; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { i } = t0; + return i; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooxbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.js new file mode 100644 index 0000000000000..971a9ff99625c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.js @@ -0,0 +1,38 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + let jsx = ( + + + + ); + return jsx; + })} + + ); +} + +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md new file mode 100644 index 0000000000000..7f86546cd4d19 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md @@ -0,0 +1,186 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function Joe({j}) { + return j; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== x || $[1] !== arr) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => { + const T0 = _temp; + return ; + }; + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = x; + $[1] = arr; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +function _temp(t0) { + const $ = _c(11); + const { i: i, j: j, k: k, x: x } = t0; + let t1; + if ($[0] !== i) { + t1 = ; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== j) { + t2 = ; + $[2] = j; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== k) { + t3 = ; + $[4] = k; + $[5] = t3; + } else { + t3 = $[5]; + } + let t4; + if ($[6] !== x || $[7] !== t1 || $[8] !== t2 || $[9] !== t3) { + t4 = ( + + {t1} + {t2} + {t3} + + ); + $[6] = x; + $[7] = t1; + $[8] = t2; + $[9] = t3; + $[10] = t4; + } else { + t4 = $[10]; + } + return t4; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== x || $[1] !== children) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = x; + $[1] = children; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { i } = t0; + return i; +} + +function Joe(t0) { + const { j } = t0; + return j; +} + +function Foo(t0) { + const { k } = t0; + return k; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfoofoofooxbarbarbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.js new file mode 100644 index 0000000000000..47d97cfc68f12 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.js @@ -0,0 +1,46 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function Joe({j}) { + return j; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md new file mode 100644 index 0000000000000..9e268227a2383 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md @@ -0,0 +1,142 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== x || $[1] !== arr) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => { + const T0 = _temp; + return ; + }; + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = x; + $[1] = arr; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +function _temp(t0) { + const $ = _c(5); + const { i: i, x: x } = t0; + let t1; + if ($[0] !== i) { + t1 = ; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== x || $[3] !== t1) { + t2 = {t1}; + $[2] = x; + $[3] = t1; + $[4] = t2; + } else { + t2 = $[4]; + } + return t2; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== x || $[1] !== children) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = x; + $[1] = children; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { i } = t0; + return i; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooxbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.js new file mode 100644 index 0000000000000..c4dcc86763b5e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.js @@ -0,0 +1,36 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md new file mode 100644 index 0000000000000..f106382d64176 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md @@ -0,0 +1,121 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + Test + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== x || $[1] !== arr) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => ( + + Test + + ); + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = x; + $[1] = arr; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== x || $[1] !== children) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = x; + $[1] = children; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { i } = t0; + return i; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooxbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js new file mode 100644 index 0000000000000..eab907e09e21d --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js @@ -0,0 +1,36 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + Test + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md new file mode 100644 index 0000000000000..77fd38aea1eb5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md @@ -0,0 +1,132 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== x || $[1] !== arr) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => ( + + + + + ); + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = x; + $[1] = arr; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== x || $[1] !== children) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = x; + $[1] = children; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { i } = t0; + return i; +} + +function Foo(t0) { + const { k } = t0; + return k; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooxbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js new file mode 100644 index 0000000000000..20c6bd934a5d0 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js @@ -0,0 +1,41 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; From 9c60cbe3d1b95d531ddcd64e0a6730db640c934e Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 17 Oct 2024 18:02:41 -0400 Subject: [PATCH 290/426] [compiler] Clean up publish script (#31278) Few small tweaks to make it easier to run adhoc publishes --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31278). * #31283 * __->__ #31278 --- .github/workflows/compiler_prereleases.yml | 2 +- compiler/scripts/release/publish.js | 60 ++++++++++++---------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/.github/workflows/compiler_prereleases.yml b/.github/workflows/compiler_prereleases.yml index c2b09dae054db..9da6fc1b08e32 100644 --- a/.github/workflows/compiler_prereleases.yml +++ b/.github/workflows/compiler_prereleases.yml @@ -49,4 +49,4 @@ jobs: - name: Publish packages to npm run: | cp ./scripts/release/ci-npmrc ~/.npmrc - scripts/release/publish.js --frfr --ci --tags ${{ inputs.dist_tag }} + scripts/release/publish.js --frfr --ci --versionName=0.0.0 --tag ${{ inputs.dist_tag }} diff --git a/compiler/scripts/release/publish.js b/compiler/scripts/release/publish.js index ef3b75a80fe6f..a7ad1a7254624 100755 --- a/compiler/scripts/release/publish.js +++ b/compiler/scripts/release/publish.js @@ -59,12 +59,19 @@ async function main() { type: 'boolean', default: false, }) - .option('tags', { - description: 'Tags to publish to npm', - type: 'string', + .option('tag', { + description: 'Tag to publish to npm', + type: 'choices', + choices: ['experimental', 'beta'], default: 'experimental', }) + .option('version-name', { + description: 'Version name', + type: 'string', + default: '0.0.0', + }) .help('help') + .strict() .parseSync(); if (argv.debug === false) { @@ -82,7 +89,7 @@ async function main() { pkgNames = [argv.packages]; } const spinner = ora( - `Preparing to publish ${ + `Preparing to publish ${argv.versionName}@${argv.tag} ${ argv.forReal === true ? '(for real)' : '(dry run)' } [debug=${argv.debug}]` ).info(); @@ -118,14 +125,15 @@ async function main() { } ); const dateString = await getDateStringForCommit(commit); - const otp = argv.ci === false ? await promptForOTP() : null; + const otp = + argv.ci === false && argv.debug === false ? await promptForOTP() : null; const {hash} = await hashElement(path.resolve(__dirname, '../..'), { encoding: 'hex', folders: {exclude: ['node_modules']}, files: {exclude: ['.DS_Store']}, }); const truncatedHash = hash.slice(0, 7); - const newVersion = `0.0.0-experimental-${truncatedHash}-${dateString}`; + const newVersion = `${argv.versionName}-${argv.tag}-${truncatedHash}-${dateString}`; for (const pkgName of pkgNames) { const pkgDir = path.resolve(__dirname, `../../packages/${pkgName}`); @@ -179,29 +187,27 @@ async function main() { spinner.succeed(`Successfully published ${pkgName} to npm`); spinner.start('Pushing tags to npm'); - if (typeof argv.tags === 'string') { - for (const tag of argv.tags.split(',')) { - try { - let opts = ['dist-tag', 'add', `${pkgName}@${newVersion}`, tag]; - if (otp != null) { - opts.push(`--otp=${otp}`); - } - if (argv.debug === true) { - spinner.info(`dry-run: npm ${opts.join(' ')}`); - } else { - await spawnHelper('npm', opts, { - cwd: pkgDir, - stdio: 'inherit', - }); - } - } catch (e) { - spinner.fail(e.toString()); - throw e; + if (typeof argv.tag === 'string') { + try { + let opts = ['dist-tag', 'add', `${pkgName}@${newVersion}`, argv.tag]; + if (otp != null) { + opts.push(`--otp=${otp}`); } - spinner.succeed( - `Successfully pushed dist-tag ${tag} for ${pkgName} to npm` - ); + if (argv.debug === true) { + spinner.info(`dry-run: npm ${opts.join(' ')}`); + } else { + await spawnHelper('npm', opts, { + cwd: pkgDir, + stdio: 'inherit', + }); + } + } catch (e) { + spinner.fail(e.toString()); + throw e; } + spinner.succeed( + `Successfully pushed dist-tag ${argv.tag} for ${pkgName} to npm` + ); } } From 25cac220d6b6576e50ec52cf87801ad036fa7bc9 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 17 Oct 2024 18:12:58 -0400 Subject: [PATCH 291/426] [ci] Allow passing various params to compiler publish script (#31283) Allow passing in a few more inputs when manually publishing. --- .github/workflows/compiler_prereleases.yml | 5 ++++- .github/workflows/compiler_prereleases_manual.yml | 14 ++++++++++++-- .github/workflows/compiler_prereleases_nightly.yml | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compiler_prereleases.yml b/.github/workflows/compiler_prereleases.yml index 9da6fc1b08e32..4f4954dd952b4 100644 --- a/.github/workflows/compiler_prereleases.yml +++ b/.github/workflows/compiler_prereleases.yml @@ -13,6 +13,9 @@ on: dist_tag: required: true type: string + version_name: + required: true + type: string secrets: NPM_TOKEN: required: true @@ -49,4 +52,4 @@ jobs: - name: Publish packages to npm run: | cp ./scripts/release/ci-npmrc ~/.npmrc - scripts/release/publish.js --frfr --ci --versionName=0.0.0 --tag ${{ inputs.dist_tag }} + scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag ${{ inputs.dist_tag }} diff --git a/.github/workflows/compiler_prereleases_manual.yml b/.github/workflows/compiler_prereleases_manual.yml index 87de411ddcb6e..3e42ae2cf200d 100644 --- a/.github/workflows/compiler_prereleases_manual.yml +++ b/.github/workflows/compiler_prereleases_manual.yml @@ -5,6 +5,15 @@ on: inputs: prerelease_commit_sha: required: false + release_channel: + required: true + type: string + dist_tag: + required: true + type: string + version_name: + required: true + type: string env: TZ: /usr/share/zoneinfo/America/Los_Angeles @@ -15,7 +24,8 @@ jobs: uses: facebook/react/.github/workflows/compiler_prereleases.yml@main with: commit_sha: ${{ inputs.prerelease_commit_sha || github.sha }} - release_channel: experimental - dist_tag: experimental + release_channel: ${{ inputs.release_channel }} + dist_tag: ${{ inputs.dist_tag }} + version_name: ${{ inputs.version_name }} secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/compiler_prereleases_nightly.yml b/.github/workflows/compiler_prereleases_nightly.yml index 90aafac4f631f..82f893aa5ef43 100644 --- a/.github/workflows/compiler_prereleases_nightly.yml +++ b/.github/workflows/compiler_prereleases_nightly.yml @@ -16,5 +16,6 @@ jobs: commit_sha: ${{ github.sha }} release_channel: experimental dist_tag: experimental + version_name: '0.0.0' secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} From 1ce58ddd672ea67631bc52e85be32962b24df6ae Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 00:20:14 -0400 Subject: [PATCH 292/426] [ci] Don't auto push to latest tag (#31284) By default let's stop pushing to the latest tag now that we have a non-experimental release. --- compiler/scripts/release/publish.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/scripts/release/publish.js b/compiler/scripts/release/publish.js index a7ad1a7254624..aa61366e8bd24 100755 --- a/compiler/scripts/release/publish.js +++ b/compiler/scripts/release/publish.js @@ -166,14 +166,7 @@ async function main() { try { await spawnHelper( 'npm', - [ - 'publish', - ...opts, - '--registry=https://registry.npmjs.org', - // For now, since the compiler is experimental only, to simplify installation we push - // to the `latest` tag - '--tag=latest', - ], + ['publish', ...opts, '--registry=https://registry.npmjs.org'], { cwd: pkgDir, stdio: 'inherit', From b8ae38f88b70f8a0ea96421a4355266aafefee7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Fri, 18 Oct 2024 12:05:20 -0400 Subject: [PATCH 293/426] Audit try/finally around console patching (#31286) Otherwise if something errors they can be left patched. [Review without whitespace](https://github.com/facebook/react/pull/31286/files?w=1) --- .../shared/DevToolsComponentStackFrame.js | 167 +++++++++--------- .../react-reconciler/src/ReactFiberHooks.js | 30 +++- .../src/ReactFiberWorkLoop.js | 19 +- packages/shared/ReactComponentStackFrame.js | 165 +++++++++-------- 4 files changed, 197 insertions(+), 184 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js b/packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js index 840a298869da8..b29ed9af7306e 100644 --- a/packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js +++ b/packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js @@ -82,105 +82,104 @@ export function describeNativeComponentFrame( const previousDispatcher = currentDispatcherRef.H; currentDispatcherRef.H = null; disableLogs(); + try { + // NOTE: keep in sync with the implementation in ReactComponentStackFrame - // NOTE: keep in sync with the implementation in ReactComponentStackFrame - - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - const RunInRootFrame = { - DetermineComponentFrameRoot(): [?string, ?string] { - let control; - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - const Fake = function () { - throw Error(); - }; - // $FlowFixMe[prop-missing] - Object.defineProperty(Fake.prototype, 'props', { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ + const RunInRootFrame = { + DetermineComponentFrameRoot(): [?string, ?string] { + let control; + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + const Fake = function () { throw Error(); - }, - }); - if (typeof Reflect === 'object' && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; + }; + // $FlowFixMe[prop-missing] + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); + }, + }); + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } + // $FlowFixMe[prop-missing] found when upgrading Flow + fn.call(Fake.prototype); } - Reflect.construct(fn, [], Fake); } else { try { - Fake.call(); + throw Error(); } catch (x) { control = x; } - // $FlowFixMe[prop-missing] found when upgrading Flow - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } - // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - const maybePromise = fn(); + // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too + const maybePromise = fn(); - // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - if (maybePromise && typeof maybePromise.catch === 'function') { - maybePromise.catch(() => {}); + // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(() => {}); + } + } + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; } } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === 'string') { - return [sample.stack, control.stack]; - } - } - return [null, null]; - }, - }; - // $FlowFixMe[prop-missing] - RunInRootFrame.DetermineComponentFrameRoot.displayName = - 'DetermineComponentFrameRoot'; - const namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - 'name', - ); - // Before ES6, the `name` property was not configurable. - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( + return [null, null]; + }, + }; + // $FlowFixMe[prop-missing] + RunInRootFrame.DetermineComponentFrameRoot.displayName = + 'DetermineComponentFrameRoot'; + const namePropDescriptor = Object.getOwnPropertyDescriptor( RunInRootFrame.DetermineComponentFrameRoot, - // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] 'name', - {value: 'DetermineComponentFrameRoot'}, ); - } + // Before ES6, the `name` property was not configurable. + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty( + RunInRootFrame.DetermineComponentFrameRoot, + // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', + {value: 'DetermineComponentFrameRoot'}, + ); + } - try { const [sampleStack, controlStack] = RunInRootFrame.DetermineComponentFrameRoot(); if (sampleStack && controlStack) { diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index 77d3e985011de..01f3b400adf70 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -1299,8 +1299,11 @@ function mountReducer( initialState = init(initialArg); if (shouldDoubleInvokeUserFnsInHooksDEV) { setIsStrictModeForDevtools(true); - init(initialArg); - setIsStrictModeForDevtools(false); + try { + init(initialArg); + } finally { + setIsStrictModeForDevtools(false); + } } } else { initialState = ((initialArg: any): S); @@ -1900,9 +1903,12 @@ function mountStateImpl(initialState: (() => S) | S): Hook { initialState = initialStateInitializer(); if (shouldDoubleInvokeUserFnsInHooksDEV) { setIsStrictModeForDevtools(true); - // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types - initialStateInitializer(); - setIsStrictModeForDevtools(false); + try { + // $FlowFixMe[incompatible-use]: Flow doesn't like mixed types + initialStateInitializer(); + } finally { + setIsStrictModeForDevtools(false); + } } } hook.memoizedState = hook.baseState = initialState; @@ -2856,8 +2862,11 @@ function mountMemo( const nextValue = nextCreate(); if (shouldDoubleInvokeUserFnsInHooksDEV) { setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); + try { + nextCreate(); + } finally { + setIsStrictModeForDevtools(false); + } } hook.memoizedState = [nextValue, nextDeps]; return nextValue; @@ -2880,8 +2889,11 @@ function updateMemo( const nextValue = nextCreate(); if (shouldDoubleInvokeUserFnsInHooksDEV) { setIsStrictModeForDevtools(true); - nextCreate(); - setIsStrictModeForDevtools(false); + try { + nextCreate(); + } finally { + setIsStrictModeForDevtools(false); + } } hook.memoizedState = [nextValue, nextDeps]; return nextValue; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index c40fc53704994..204776075d49f 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -3987,15 +3987,18 @@ function doubleInvokeEffectsOnFiber( shouldDoubleInvokePassiveEffects: boolean = true, ) { setIsStrictModeForDevtools(true); - disappearLayoutEffects(fiber); - if (shouldDoubleInvokePassiveEffects) { - disconnectPassiveEffect(fiber); - } - reappearLayoutEffects(root, fiber.alternate, fiber, false); - if (shouldDoubleInvokePassiveEffects) { - reconnectPassiveEffects(root, fiber, NoLanes, null, false); + try { + disappearLayoutEffects(fiber); + if (shouldDoubleInvokePassiveEffects) { + disconnectPassiveEffect(fiber); + } + reappearLayoutEffects(root, fiber.alternate, fiber, false); + if (shouldDoubleInvokePassiveEffects) { + reconnectPassiveEffects(root, fiber, NoLanes, null, false); + } + } finally { + setIsStrictModeForDevtools(false); } - setIsStrictModeForDevtools(false); } function doubleInvokeEffectsInDEVIfNecessary( diff --git a/packages/shared/ReactComponentStackFrame.js b/packages/shared/ReactComponentStackFrame.js index dd0cff90b99c4..bef56120ff4a2 100644 --- a/packages/shared/ReactComponentStackFrame.js +++ b/packages/shared/ReactComponentStackFrame.js @@ -103,103 +103,102 @@ export function describeNativeComponentFrame( ReactSharedInternals.H = null; disableLogs(); } - - /** - * Finding a common stack frame between sample and control errors can be - * tricky given the different types and levels of stack trace truncation from - * different JS VMs. So instead we'll attempt to control what that common - * frame should be through this object method: - * Having both the sample and control errors be in the function under the - * `DescribeNativeComponentFrameRoot` property, + setting the `name` and - * `displayName` properties of the function ensures that a stack - * frame exists that has the method name `DescribeNativeComponentFrameRoot` in - * it for both control and sample stacks. - */ - const RunInRootFrame = { - DetermineComponentFrameRoot(): [?string, ?string] { - let control; - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - const Fake = function () { - throw Error(); - }; - // $FlowFixMe[prop-missing] - Object.defineProperty(Fake.prototype, 'props', { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. + try { + /** + * Finding a common stack frame between sample and control errors can be + * tricky given the different types and levels of stack trace truncation from + * different JS VMs. So instead we'll attempt to control what that common + * frame should be through this object method: + * Having both the sample and control errors be in the function under the + * `DescribeNativeComponentFrameRoot` property, + setting the `name` and + * `displayName` properties of the function ensures that a stack + * frame exists that has the method name `DescribeNativeComponentFrameRoot` in + * it for both control and sample stacks. + */ + const RunInRootFrame = { + DetermineComponentFrameRoot(): [?string, ?string] { + let control; + try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + const Fake = function () { throw Error(); - }, - }); - if (typeof Reflect === 'object' && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; + }; + // $FlowFixMe[prop-missing] + Object.defineProperty(Fake.prototype, 'props', { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); + }, + }); + if (typeof Reflect === 'object' && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } + // $FlowFixMe[prop-missing] found when upgrading Flow + fn.call(Fake.prototype); } - Reflect.construct(fn, [], Fake); } else { try { - Fake.call(); + throw Error(); } catch (x) { control = x; } - // $FlowFixMe[prop-missing] found when upgrading Flow - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } - // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - const maybePromise = fn(); + // TODO(luna): This will currently only throw if the function component + // tries to access React/ReactDOM/props. We should probably make this throw + // in simple components too + const maybePromise = fn(); - // If the function component returns a promise, it's likely an async - // component, which we don't yet support. Attach a noop catch handler to - // silence the error. - // TODO: Implement component stacks for async client components? - if (maybePromise && typeof maybePromise.catch === 'function') { - maybePromise.catch(() => {}); + // If the function component returns a promise, it's likely an async + // component, which we don't yet support. Attach a noop catch handler to + // silence the error. + // TODO: Implement component stacks for async client components? + if (maybePromise && typeof maybePromise.catch === 'function') { + maybePromise.catch(() => {}); + } + } + } catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === 'string') { + return [sample.stack, control.stack]; } } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === 'string') { - return [sample.stack, control.stack]; - } - } - return [null, null]; - }, - }; - // $FlowFixMe[prop-missing] - RunInRootFrame.DetermineComponentFrameRoot.displayName = - 'DetermineComponentFrameRoot'; - const namePropDescriptor = Object.getOwnPropertyDescriptor( - RunInRootFrame.DetermineComponentFrameRoot, - 'name', - ); - // Before ES6, the `name` property was not configurable. - if (namePropDescriptor && namePropDescriptor.configurable) { - // V8 utilizes a function's `name` property when generating a stack trace. - Object.defineProperty( + return [null, null]; + }, + }; + // $FlowFixMe[prop-missing] + RunInRootFrame.DetermineComponentFrameRoot.displayName = + 'DetermineComponentFrameRoot'; + const namePropDescriptor = Object.getOwnPropertyDescriptor( RunInRootFrame.DetermineComponentFrameRoot, - // Configurable properties can be updated even if its writable descriptor - // is set to `false`. - // $FlowFixMe[cannot-write] 'name', - {value: 'DetermineComponentFrameRoot'}, ); - } + // Before ES6, the `name` property was not configurable. + if (namePropDescriptor && namePropDescriptor.configurable) { + // V8 utilizes a function's `name` property when generating a stack trace. + Object.defineProperty( + RunInRootFrame.DetermineComponentFrameRoot, + // Configurable properties can be updated even if its writable descriptor + // is set to `false`. + // $FlowFixMe[cannot-write] + 'name', + {value: 'DetermineComponentFrameRoot'}, + ); + } - try { const [sampleStack, controlStack] = RunInRootFrame.DetermineComponentFrameRoot(); if (sampleStack && controlStack) { From 35b63ca90db4d5abe3bba6e5a47466d2c7b5a836 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 13:24:30 -0400 Subject: [PATCH 294/426] [ci:compiler] Only add latest tag to non-experimental (#31288) It turns out npm sets the latest tag by default so simply removing it didn't change the previous behavior. The `latest` tag is typically used for stable release versions, and other tags for unstable versions such as prereleases. Since the compiler is still in prerelease, let's set the latest tag only for non-experimental releases to help signal which version is the safest to try out. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31288). * #31289 * __->__ #31288 --- compiler/scripts/release/publish.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/scripts/release/publish.js b/compiler/scripts/release/publish.js index aa61366e8bd24..23ca5300620f9 100755 --- a/compiler/scripts/release/publish.js +++ b/compiler/scripts/release/publish.js @@ -163,6 +163,21 @@ async function main() { if (otp != null) { opts.push(`--otp=${otp}`); } + /** + * Typically, the `latest` tag is reserved for stable package versions. Since the the compiler + * is still pre-release, until we have a stable release let's only add the + * `latest` tag to non-experimental releases. + * + * `latest` is added by default, so we only override it for experimental releases so that + * those don't get the `latest` tag. + * + * TODO: Update this when we have a stable release. + */ + if (argv.tag === 'experimental') { + opts.push('--tag=experimental'); + } else { + opts.push('--tag=latest'); + } try { await spawnHelper( 'npm', From d57217544aa2e98ff6370b8bf5f6aafb253fa642 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 13:32:26 -0400 Subject: [PATCH 295/426] [fixture] Update compiler to use latest package (#31289) Pins the compiler to the latest version in our fixture app. --- .../runtime-compat/app-18/package.json | 4 ++-- .../fixtures/runtime-compat/app-18/yarn.lock | 18 +++++++++--------- .../runtime-compat/app-19/package.json | 2 +- .../fixtures/runtime-compat/app-19/yarn.lock | 18 +++++++++--------- .../fixtures/runtime-compat/lib/package.json | 4 ++-- compiler/fixtures/runtime-compat/lib/yarn.lock | 16 ++++++++-------- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/fixtures/runtime-compat/app-18/package.json b/compiler/fixtures/runtime-compat/app-18/package.json index ef303670ad390..cccdd5e176172 100644 --- a/compiler/fixtures/runtime-compat/app-18/package.json +++ b/compiler/fixtures/runtime-compat/app-18/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "react": "^18.3.1", - "react-compiler-runtime": "0.0.0-experimental-8d8e73f-20241009", + "react-compiler-runtime": "19.0.0-beta-9ee70a1-20241017", "react-dom": "^18.3.1", "runtime-compat-lib": "file:../lib" }, @@ -20,7 +20,7 @@ "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", - "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009", + "babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017", "eslint": "^9.11.1", "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", diff --git a/compiler/fixtures/runtime-compat/app-18/yarn.lock b/compiler/fixtures/runtime-compat/app-18/yarn.lock index 59cf6935a7413..aeaa712ae6bdf 100644 --- a/compiler/fixtures/runtime-compat/app-18/yarn.lock +++ b/compiler/fixtures/runtime-compat/app-18/yarn.lock @@ -761,10 +761,10 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -babel-plugin-react-compiler@0.0.0-experimental-58c2b1c-20241009: - version "0.0.0-experimental-58c2b1c-20241009" - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-58c2b1c-20241009.tgz#a840860c5da30cbc25db0671b9c715602539a175" - integrity sha512-/DSwpfz7c1hK5dpxxlLxQJtvXCF3RjN3ZCaJ43NM4BEvzTpaS0C0jasXVBEUIFumBcdaoirFbfZkyk9htY+6Xw== +babel-plugin-react-compiler@19.0.0-beta-9ee70a1-20241017: + version "19.0.0-beta-9ee70a1-20241017" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-9ee70a1-20241017.tgz#734036661d70e0d91c5f64414b31220ecc0019d2" + integrity sha512-AkSce5YYHcreFtuvzI9xnP2kwoYkub8Go3yrz7cPbbCE6oIhFxESbPWJVgye7yZckXuzEZYO4JSE8tq/U0oVfA== dependencies: "@babel/generator" "7.2.0" "@babel/types" "^7.19.0" @@ -1440,10 +1440,10 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: - version "0.0.0-experimental-8d8e73f-20241009" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" - integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== +react-compiler-runtime@19.0.0-beta-9ee70a1-20241017: + version "19.0.0-beta-9ee70a1-20241017" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-9ee70a1-20241017.tgz#ca35ba4ec80f2412fcdbfb911831308670acc13a" + integrity sha512-hVrlYbVacwEdZi08RUxSwIzZR2/+WxUsWRa7mjViRhqcqUYK+7u8UEVZoJrF5/gsCHMU9PhJRvolygSCaaE0nA== react-dom@^18.3.1: version "18.3.1" @@ -1515,7 +1515,7 @@ run-parallel@^1.1.9: "runtime-compat-lib@file:../lib": version "0.0.0" dependencies: - react-compiler-runtime "0.0.0-experimental-8d8e73f-20241009" + react-compiler-runtime "19.0.0-beta-9ee70a1-20241017" scheduler@^0.23.2: version "0.23.2" diff --git a/compiler/fixtures/runtime-compat/app-19/package.json b/compiler/fixtures/runtime-compat/app-19/package.json index 3c1ba6859142d..3e92952c9de47 100644 --- a/compiler/fixtures/runtime-compat/app-19/package.json +++ b/compiler/fixtures/runtime-compat/app-19/package.json @@ -19,7 +19,7 @@ "@types/react": "^18.3.10", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.2", - "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009", + "babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017", "eslint": "^9.11.1", "eslint-plugin-react-hooks": "^5.1.0-rc.0", "eslint-plugin-react-refresh": "^0.4.12", diff --git a/compiler/fixtures/runtime-compat/app-19/yarn.lock b/compiler/fixtures/runtime-compat/app-19/yarn.lock index 7d22e4cd3a7c8..ddffd131007ce 100644 --- a/compiler/fixtures/runtime-compat/app-19/yarn.lock +++ b/compiler/fixtures/runtime-compat/app-19/yarn.lock @@ -761,10 +761,10 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -babel-plugin-react-compiler@0.0.0-experimental-58c2b1c-20241009: - version "0.0.0-experimental-58c2b1c-20241009" - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-58c2b1c-20241009.tgz#a840860c5da30cbc25db0671b9c715602539a175" - integrity sha512-/DSwpfz7c1hK5dpxxlLxQJtvXCF3RjN3ZCaJ43NM4BEvzTpaS0C0jasXVBEUIFumBcdaoirFbfZkyk9htY+6Xw== +babel-plugin-react-compiler@19.0.0-beta-9ee70a1-20241017: + version "19.0.0-beta-9ee70a1-20241017" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-9ee70a1-20241017.tgz#734036661d70e0d91c5f64414b31220ecc0019d2" + integrity sha512-AkSce5YYHcreFtuvzI9xnP2kwoYkub8Go3yrz7cPbbCE6oIhFxESbPWJVgye7yZckXuzEZYO4JSE8tq/U0oVfA== dependencies: "@babel/generator" "7.2.0" "@babel/types" "^7.19.0" @@ -1440,10 +1440,10 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: - version "0.0.0-experimental-8d8e73f-20241009" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" - integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== +react-compiler-runtime@19.0.0-beta-9ee70a1-20241017: + version "19.0.0-beta-9ee70a1-20241017" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-9ee70a1-20241017.tgz#ca35ba4ec80f2412fcdbfb911831308670acc13a" + integrity sha512-hVrlYbVacwEdZi08RUxSwIzZR2/+WxUsWRa7mjViRhqcqUYK+7u8UEVZoJrF5/gsCHMU9PhJRvolygSCaaE0nA== react-dom@19.0.0-beta-26f2496093-20240514: version "19.0.0-beta-26f2496093-20240514" @@ -1512,7 +1512,7 @@ run-parallel@^1.1.9: "runtime-compat-lib@file:../lib": version "0.0.0" dependencies: - react-compiler-runtime "0.0.0-experimental-8d8e73f-20241009" + react-compiler-runtime "19.0.0-beta-9ee70a1-20241017" scheduler@0.25.0-beta-26f2496093-20240514: version "0.25.0-beta-26f2496093-20240514" diff --git a/compiler/fixtures/runtime-compat/lib/package.json b/compiler/fixtures/runtime-compat/lib/package.json index ed8cb7b821ad3..facfbb152a956 100644 --- a/compiler/fixtures/runtime-compat/lib/package.json +++ b/compiler/fixtures/runtime-compat/lib/package.json @@ -14,7 +14,7 @@ "@babel/preset-env": "^7.25.7", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-json": "^6.1.0", - "babel-plugin-react-compiler": "0.0.0-experimental-58c2b1c-20241009", + "babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017", "@rollup/plugin-terser": "^0.4.4", "react": "19.0.0-beta-26f2496093-20240514", "react-dom": "19.0.0-beta-26f2496093-20240514", @@ -24,7 +24,7 @@ "rollup-plugin-prettier": "^4.1.1" }, "dependencies": { - "react-compiler-runtime": "0.0.0-experimental-8d8e73f-20241009" + "react-compiler-runtime": "19.0.0-beta-9ee70a1-20241017" }, "peerDependencies": { "react": "^18 || ^19" diff --git a/compiler/fixtures/runtime-compat/lib/yarn.lock b/compiler/fixtures/runtime-compat/lib/yarn.lock index fee616b98adbe..72cebdb2642a0 100644 --- a/compiler/fixtures/runtime-compat/lib/yarn.lock +++ b/compiler/fixtures/runtime-compat/lib/yarn.lock @@ -1260,10 +1260,10 @@ babel-plugin-polyfill-regenerator@^0.6.1: dependencies: "@babel/helper-define-polyfill-provider" "^0.6.2" -babel-plugin-react-compiler@0.0.0-experimental-58c2b1c-20241009: - version "0.0.0-experimental-58c2b1c-20241009" - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-0.0.0-experimental-58c2b1c-20241009.tgz#a840860c5da30cbc25db0671b9c715602539a175" - integrity sha512-/DSwpfz7c1hK5dpxxlLxQJtvXCF3RjN3ZCaJ43NM4BEvzTpaS0C0jasXVBEUIFumBcdaoirFbfZkyk9htY+6Xw== +babel-plugin-react-compiler@19.0.0-beta-9ee70a1-20241017: + version "19.0.0-beta-9ee70a1-20241017" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-9ee70a1-20241017.tgz#734036661d70e0d91c5f64414b31220ecc0019d2" + integrity sha512-AkSce5YYHcreFtuvzI9xnP2kwoYkub8Go3yrz7cPbbCE6oIhFxESbPWJVgye7yZckXuzEZYO4JSE8tq/U0oVfA== dependencies: "@babel/generator" "7.2.0" "@babel/types" "^7.19.0" @@ -1829,10 +1829,10 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -react-compiler-runtime@0.0.0-experimental-8d8e73f-20241009: - version "0.0.0-experimental-8d8e73f-20241009" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0-experimental-8d8e73f-20241009.tgz#c5a1a99c79ac8f8e8cf75b8ea89394b2ab7a77ad" - integrity sha512-TEOS8csCfa/xSNt8ft9yRAimOJNetQIOuTgMFU2rv3dhDUOpM3e/Jrv+55uGUKMUYK6kCBV4QYsviLl2c8JfOg== +react-compiler-runtime@19.0.0-beta-9ee70a1-20241017: + version "19.0.0-beta-9ee70a1-20241017" + resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-9ee70a1-20241017.tgz#ca35ba4ec80f2412fcdbfb911831308670acc13a" + integrity sha512-hVrlYbVacwEdZi08RUxSwIzZR2/+WxUsWRa7mjViRhqcqUYK+7u8UEVZoJrF5/gsCHMU9PhJRvolygSCaaE0nA== react-dom@19.0.0-beta-26f2496093-20240514: version "19.0.0-beta-26f2496093-20240514" From ee6ca23b248a7bdcd973101bda86723ed3c46390 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 14:09:07 -0400 Subject: [PATCH 296/426] [playground] Upgrade to Next 15 (#31291) This was previously blocked because the playground was a part of the compiler's yarn workspace and there was some funky hoisting going on. Now that we are decoupled we can upgrade to Next 15, which hopefully should improve build times. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31291). * #31293 * #31292 * __->__ #31291 --- compiler/apps/playground/babel.config.js | 21 - compiler/apps/playground/next-env.d.ts | 2 +- compiler/apps/playground/next.config.js | 3 + compiler/apps/playground/package.json | 17 +- compiler/apps/playground/yarn.lock | 667 ++++++++++++++--------- 5 files changed, 424 insertions(+), 286 deletions(-) delete mode 100644 compiler/apps/playground/babel.config.js diff --git a/compiler/apps/playground/babel.config.js b/compiler/apps/playground/babel.config.js deleted file mode 100644 index f65e0a2a79046..0000000000000 --- a/compiler/apps/playground/babel.config.js +++ /dev/null @@ -1,21 +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. - */ - -module.exports = function (api) { - api.cache(true); - return { - presets: ['next/babel'], - plugins: [ - [ - 'babel-plugin-react-compiler', - { - target: '18', - }, - ], - ], - }; -}; diff --git a/compiler/apps/playground/next-env.d.ts b/compiler/apps/playground/next-env.d.ts index 4f11a03dc6cc3..40c3d68096c27 100644 --- a/compiler/apps/playground/next-env.d.ts +++ b/compiler/apps/playground/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/compiler/apps/playground/next.config.js b/compiler/apps/playground/next.config.js index 0082e02532026..fc8a9492e4ed7 100644 --- a/compiler/apps/playground/next.config.js +++ b/compiler/apps/playground/next.config.js @@ -9,6 +9,9 @@ const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const path = require('path'); const nextConfig = { + experimental: { + reactCompiler: true, + }, reactStrictMode: true, webpack: (config, options) => { // Load *.d.ts files as strings using https://webpack.js.org/guides/asset-modules/#source-assets. diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index c3f57499ce4d6..95fc72fd20a7d 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -34,28 +34,31 @@ "invariant": "^2.2.4", "lz-string": "^1.5.0", "monaco-editor": "^0.34.1", - "next": "^13.5.6", + "next": "15.0.0-canary.197", "notistack": "^3.0.0-alpha.7", "prettier": "^3.3.3", "pretty-format": "^29.3.1", "re-resizable": "^6.9.16", - "react": "18.3.1", - "react-compiler-runtime": "*", - "react-dom": "18.3.1" + "react": "19.0.0-rc-77b637d6-20241016", + "react-dom": "19.0.0-rc-77b637d6-20241016" }, "devDependencies": { "@types/node": "18.11.9", - "@types/react": "18.3.9", - "@types/react-dom": "18.3.0", + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", "autoprefixer": "^10.4.13", "clsx": "^1.2.1", "concurrently": "^7.4.0", "eslint": "^8.28.0", - "eslint-config-next": "^13.5.6", + "eslint-config-next": "15.0.0-canary.197", "hermes-parser": "^0.22.0", "monaco-editor-webpack-plugin": "^7.1.0", "postcss": "^8.4.31", "tailwindcss": "^3.2.4", "wait-on": "^7.2.0" + }, + "resolutions": { + "@types/react": "npm:types-react@19.0.0-rc.1", + "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1" } } diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index 716649103e6af..493ba6fbf9ad7 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -336,14 +336,21 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" -"@eslint-community/eslint-utils@^4.2.0": +"@emnapi/runtime@^1.2.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.3.1.tgz#0fcaa575afc31f455fd33534c19381cfce6c6f60" + integrity sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw== + dependencies: + tslib "^2.4.0" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": version "4.11.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== @@ -404,6 +411,119 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@img/sharp-darwin-arm64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08" + integrity sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.0.4" + +"@img/sharp-darwin-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61" + integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.0.4" + +"@img/sharp-libvips-darwin-arm64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f" + integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg== + +"@img/sharp-libvips-darwin-x64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062" + integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== + +"@img/sharp-libvips-linux-arm64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704" + integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA== + +"@img/sharp-libvips-linux-arm@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197" + integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g== + +"@img/sharp-libvips-linux-s390x@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce" + integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA== + +"@img/sharp-libvips-linux-x64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0" + integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw== + +"@img/sharp-libvips-linuxmusl-arm64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5" + integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA== + +"@img/sharp-libvips-linuxmusl-x64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff" + integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw== + +"@img/sharp-linux-arm64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22" + integrity sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.0.4" + +"@img/sharp-linux-arm@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff" + integrity sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.0.5" + +"@img/sharp-linux-s390x@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667" + integrity sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.0.4" + +"@img/sharp-linux-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb" + integrity sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.0.4" + +"@img/sharp-linuxmusl-arm64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b" + integrity sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" + +"@img/sharp-linuxmusl-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48" + integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.0.4" + +"@img/sharp-wasm32@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1" + integrity sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg== + dependencies: + "@emnapi/runtime" "^1.2.0" + +"@img/sharp-win32-ia32@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9" + integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ== + +"@img/sharp-win32-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342" + integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -469,62 +589,57 @@ dependencies: "@monaco-editor/loader" "^1.4.0" -"@next/env@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/env/-/env-13.5.7.tgz#5006f4460a7fa598a03e1c2aa4e59e45c71082d3" - integrity sha512-uVuRqoj28Ys/AI/5gVEgRAISd0KWI0HRjOO1CTpNgmX3ZsHb5mdn14Y59yk0IxizXdo7ZjsI2S7qbWnO+GNBcA== - -"@next/eslint-plugin-next@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.7.tgz#9a8cd86a7a27b8f370ec3b130e598688c869bdc6" - integrity sha512-c4vuEOOXeib4js5gDq+zFqAAdRGXX6T0d+zFETiQkRwy7vyj5lBov1dW0Z09nDst2lvxo7VEcKrQMUBH5Vgx7Q== - dependencies: - glob "7.1.7" - -"@next/swc-darwin-arm64@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.7.tgz#b99b91c04a884ba1272a3bd5db2b6f47a5bb10c2" - integrity sha512-7SxmxMex45FvKtRoP18eftrDCMyL6WQVYJSEE/s7A1AW/fCkznxjEShKet2iVVzf89gWp8HbXGaL4hCaseux6g== - -"@next/swc-darwin-x64@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.7.tgz#0a30d1c40430ed09ef4384bd90148e68badbf5e5" - integrity sha512-6iENvgyIkGFLFszBL4b1VfEogKC3TDPEB6/P/lgxmgXVXIV09Q4or1MVn+U/tYyYmm7oHMZ3oxGpHAyJ80nA6g== - -"@next/swc-linux-arm64-gnu@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.7.tgz#f6464e423186494d44ae9544c76b50e661682bc0" - integrity sha512-P42jDX56wu9zEdVI+Xv4zyTeXB3DpqgE1Gb4bWrc0s2RIiDYr6uKBprnOs1hCGIwfVyByxyTw5Va66QCdFFNUg== - -"@next/swc-linux-arm64-musl@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.7.tgz#88b62e006d00fc31359723f96cbd601132812873" - integrity sha512-A06vkj+8X+tLRzSja5REm/nqVOCzR+x5Wkw325Q/BQRyRXWGCoNbQ6A+BR5M86TodigrRfI3lUZEKZKe3QJ9Bg== - -"@next/swc-linux-x64-gnu@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.7.tgz#68d31a7c75f1b0dbc408f9fe49ac878c6723446c" - integrity sha512-UdHm7AlxIbdRdMsK32cH0EOX4OmzAZ4Xm+UVlS0YdvwLkI3pb7AoBEoVMG5H0Wj6Wpz6GNkrFguHTRLymTy6kw== - -"@next/swc-linux-x64-musl@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.7.tgz#09c9c3c667abd55f2af0b4e464342350baeabdb3" - integrity sha512-c50Y8xBKU16ZGj038H6C13iedRglxvdQHD/1BOtes56gwUrIRDX2Nkzn3mYtpz3Wzax0gfAF9C0Nqljt93IxvA== - -"@next/swc-win32-arm64-msvc@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.7.tgz#3314966f960a22ee95adb8285e0927c9e4ba7205" - integrity sha512-NcUx8cmkA+JEp34WNYcKW6kW2c0JBhzJXIbw+9vKkt9m/zVJ+KfizlqmoKf04uZBtzFN6aqE2Fyv2MOd021WIA== - -"@next/swc-win32-ia32-msvc@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.7.tgz#fd118f3bd5a87453b252eb3c5fae54ddce035026" - integrity sha512-wXp+/3NVcuyJDED6gJiLXs5dqHaWO7moAB6aBtjlKZvsxBDxpcyjsfRbtHPeYtaT20zCkmPs69H0K25lrVZmlA== - -"@next/swc-win32-x64-msvc@13.5.7": - version "13.5.7" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.7.tgz#3eff03a5a80281449c58fece85a780c1e6e3594b" - integrity sha512-PLyD3Dl6jTTkLG8AoqhPGd5pXtSs8wbqIhWPQt3yEMfnYld/dGYuF2YPs3YHaVFrijCIF9pXY3+QOyvP23Zn7g== +"@next/env@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.0-canary.197.tgz#d5ae98dab7374d68dcef319f26cd897c0bca16fe" + integrity sha512-xkJbvMANutTqIJ3FPAGtELz5d7ZF/nyNJnpaLAWxV87dF0x8ZVR/uo3MCsrN/jitWfoiEJDav90VeUcYAfhbZA== + +"@next/eslint-plugin-next@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.0-canary.197.tgz#2f66f0bc2b81a267e3e424786b9615bb3724bfbd" + integrity sha512-PawKr9jxAjXr8P4p1OtpIX0NyopglQsRG3hDtmZ9RAxNNtheWwIJf3YeaRsXnlf0m8iljAN3MiOZve39GN1FLQ== + dependencies: + fast-glob "3.3.1" + +"@next/swc-darwin-arm64@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.0-canary.197.tgz#705f7169b424650a012d8ecb170735211ab818e2" + integrity sha512-WDyzAx/nu1RTg1X27+YNApQLn5cGaCGhOsBuIpPy7U0P+hW2CdZ0YhHprRxA9pIX1CsdvY61BcngkTQOtR3g1w== + +"@next/swc-darwin-x64@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.0-canary.197.tgz#623940d6cbe1c76423ff4e5d3c2ac3cfd3964ce2" + integrity sha512-updImRT6rAV9nhHn8mXW2fYM02JalJt8ogTa3YspHSYtG+ueqdKhXZo+a+YyJ9N/rgLJwtPZnEEZ/SMDbzASvQ== + +"@next/swc-linux-arm64-gnu@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.0-canary.197.tgz#e751ecc349ccfc8ef9689bcabb6c4b405551ffbf" + integrity sha512-FgDBzFwMA/bunjONCwvN0ImmYEqMG4c7544iB6Aj798WF5tGr8hGhSpsjml1EaWq2X3wO3UHtRU5RBUGz+WxGg== + +"@next/swc-linux-arm64-musl@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.0-canary.197.tgz#b7ea38d3dd90040124781d54d8e92fe0eadcf6a0" + integrity sha512-FvNQk7vxPtmesKdR15XoVm8wJUCUXVmbvdwms9f7pXIesdtGvd/eBBQ4e9njU3na1FPrwNzOjV/5DIp8O+ZH0g== + +"@next/swc-linux-x64-gnu@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.0-canary.197.tgz#f9fc075c72caf3e3274cd5fee4d5857b79751b9a" + integrity sha512-cTq5mSGMlYPfn2w3QD6+3kTqqiHrtCfTGfh484Ndmm2EQMUmKafx7s+ovCFMftJoICbQtXCP2ynX/+3GmEF4TQ== + +"@next/swc-linux-x64-musl@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.0-canary.197.tgz#9db818a0f2244ca67f67dddd9f5d31484f481336" + integrity sha512-R/5eZn9u4YwYLid/kUgcFNhON33UxvZN3mbmpxVaZraBGsU+rsXPxl4BSPD070GnH1xwq//3j84I/FfxgwN0kg== + +"@next/swc-win32-arm64-msvc@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.0-canary.197.tgz#263fb82c4dba585d15dfeea681bf38efd8a712a1" + integrity sha512-87P+1a3egZXALB1FB2OMDMp12rUVavuzl3xG9Cqz2aLKxhz+1MD38lKf3W4dsNxJ8lGGygCIeAd1d95aGJybhg== + +"@next/swc-win32-x64-msvc@15.0.0-canary.197": + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.0-canary.197.tgz#bf791a77927ea5adc40f5bf54cb7ed7ac0b75e9f" + integrity sha512-Tw2yrY5FYt08aoz+OKK01kSKaoSfDba3ouwfNoPZnXIGLi/lcKv9ThDpwecj0Qs8cgidNJBba+U52lkkxL94Xw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -569,7 +684,7 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@rushstack/eslint-patch@^1.3.3": +"@rushstack/eslint-patch@^1.10.3": version "1.10.4" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz#427d5549943a9c6fce808e39ea64dbe60d4047f1" integrity sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA== @@ -596,10 +711,15 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@swc/helpers@0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d" - integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw== +"@swc/counter@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/helpers@0.5.13": + version "0.5.13" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c" + integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w== dependencies: tslib "^2.4.0" @@ -613,71 +733,100 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg== -"@types/prop-types@*": - version "15.7.13" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" - integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== - -"@types/react-dom@18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== +"@types/react-dom@npm:types-react-dom@19.0.0-rc.1": + version "19.0.0-rc.1" + resolved "https://registry.yarnpkg.com/types-react-dom/-/types-react-dom-19.0.0-rc.1.tgz#1d544d02c5df2a82d87c2eff979afa2e21a8317a" + integrity sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.3.9": - version "18.3.9" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.9.tgz#2cdf5f425ec8a133d67e9e3673909738b783db20" - integrity sha512-+BpAVyTpJkNWWSSnaLBk6ePpHLOGJKnEQNbINNovPWzvEUyAe3e+/d494QdEh71RekM/qV7lw6jzf1HGrJyAtQ== +"@types/react@*", "@types/react@npm:types-react@19.0.0-rc.1": + version "19.0.0-rc.1" + resolved "https://registry.yarnpkg.com/types-react/-/types-react-19.0.0-rc.1.tgz#576d1a702f6d0cc5b24813a293913e5cbfeaa647" + integrity sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ== dependencies: - "@types/prop-types" "*" csstype "^3.0.2" -"@typescript-eslint/parser@^5.4.2 || ^6.0.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" - integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== +"@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.10.0.tgz#9c8218ed62f9a322df10ded7c34990f014df44f2" + integrity sha512-phuB3hoP7FFKbRXxjl+DRlQDuJqhpOnm5MmtROXyWi3uS/Xg2ZXqiQfcG2BJHiN4QKyzdOJi3NEn/qTnjUlkmQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.10.0" + "@typescript-eslint/type-utils" "8.10.0" + "@typescript-eslint/utils" "8.10.0" + "@typescript-eslint/visitor-keys" "8.10.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.10.0.tgz#3cbe7206f5e42835878a74a76da533549f977662" + integrity sha512-E24l90SxuJhytWJ0pTQydFT46Nk0Z+bsLKo/L8rtQSL93rQ6byd1V/QbDpHUTdLPOMsBCcYXZweADNCfOCmOAg== dependencies: - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/scope-manager" "8.10.0" + "@typescript-eslint/types" "8.10.0" + "@typescript-eslint/typescript-estree" "8.10.0" + "@typescript-eslint/visitor-keys" "8.10.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" - integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== +"@typescript-eslint/scope-manager@8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.10.0.tgz#606ffe18314d7b5c2f118f2f02aaa2958107a19c" + integrity sha512-AgCaEjhfql9MDKjMUxWvH7HjLeBqMCBfIaBbzzIcBbQPZE7CPh1m6FF+L75NUMJFMLYhCywJXIDEMa3//1A0dw== dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/types" "8.10.0" + "@typescript-eslint/visitor-keys" "8.10.0" -"@typescript-eslint/types@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" - integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== +"@typescript-eslint/type-utils@8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.10.0.tgz#99f1d2e21f8c74703e7d9c4a67a87271eaf57597" + integrity sha512-PCpUOpyQSpxBn230yIcK+LeCQaXuxrgCm2Zk1S+PTIRJsEfU6nJ0TtwyH8pIwPK/vJoA+7TZtzyAJSGBz+s/dg== + dependencies: + "@typescript-eslint/typescript-estree" "8.10.0" + "@typescript-eslint/utils" "8.10.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.10.0.tgz#eb29c4bc2ed23489348c297469c76d28c38fb618" + integrity sha512-k/E48uzsfJCRRbGLapdZgrX52csmWJ2rcowwPvOZ8lwPUv3xW6CcFeJAXgx4uJm+Ge4+a4tFOkdYvSpxhRhg1w== -"@typescript-eslint/typescript-estree@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" - integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== +"@typescript-eslint/typescript-estree@8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.10.0.tgz#36cc66e06c5f44d6781f95cb03b132e985273a33" + integrity sha512-3OE0nlcOHaMvQ8Xu5gAfME3/tWVDpb/HxtpUZ1WeOAksZ/h/gwrBzCklaGzwZT97/lBbbxJ16dMA98JMEngW4w== dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/types" "8.10.0" + "@typescript-eslint/visitor-keys" "8.10.0" debug "^4.3.4" - globby "^11.1.0" + fast-glob "^3.3.2" is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/visitor-keys@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" - integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== +"@typescript-eslint/utils@8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.10.0.tgz#d78d1ce3ea3d2a88a2593ebfb1c98490131d00bf" + integrity sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w== dependencies: - "@typescript-eslint/types" "6.21.0" - eslint-visitor-keys "^3.4.1" + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.10.0" + "@typescript-eslint/types" "8.10.0" + "@typescript-eslint/typescript-estree" "8.10.0" + +"@typescript-eslint/visitor-keys@8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.10.0.tgz#7ce4c0c3b82140415c9cd9babe09e0000b4e9979" + integrity sha512-k8nekgqwr7FadWk548Lfph6V3r9OVqjzAIVskE7orMZR23cGJjAOVazsZSJW+ElyjfTM4wx/1g88Mi70DDtG9A== + dependencies: + "@typescript-eslint/types" "8.10.0" + eslint-visitor-keys "^3.4.3" "@ungap/structured-clone@^1.2.0": version "1.2.0" @@ -800,11 +949,6 @@ array-includes@^3.1.6, array-includes@^3.1.8: get-intrinsic "^1.2.4" is-string "^1.0.7" -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - array.prototype.findlast@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" @@ -997,7 +1141,12 @@ camelcase-css@^2.0.1: resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== -caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663: +caniuse-lite@^1.0.30001579: + version "1.0.30001669" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3" + integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== + +caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663: version "1.0.30001664" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz#d588d75c9682d3301956b05a3749652a80677df4" integrity sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g== @@ -1072,11 +1221,27 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -1238,18 +1403,16 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +detect-libc@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - dlv@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" @@ -1448,20 +1611,21 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-next@^13.5.6: - version "13.5.7" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.5.7.tgz#fc5d86b22364c93d9279acab2a6f4848c4dbccaf" - integrity sha512-pdeUuL9KZ8qFzzKqCbxk6FXwG9dNEnot/3+qSFJqxdSGgkFUH8cgZus/meyCi2S0cTAsDbBEE030E6zvL9pUYQ== +eslint-config-next@15.0.0-canary.197: + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.0.0-canary.197.tgz#06e275c0890f5348be51724dda43a9b2eada12b1" + integrity sha512-YkcBlszYqUwatcuWJzUkJxcb7ztwP6w+/xUKYTRiWhmZTH07YOtG0oHHkWqNqPb0NZ0B65wSKLnZAAPpuLyFGA== dependencies: - "@next/eslint-plugin-next" "13.5.7" - "@rushstack/eslint-patch" "^1.3.3" - "@typescript-eslint/parser" "^5.4.2 || ^6.0.0" + "@next/eslint-plugin-next" "15.0.0-canary.197" + "@rushstack/eslint-patch" "^1.10.3" + "@typescript-eslint/eslint-plugin" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" eslint-import-resolver-node "^0.3.6" eslint-import-resolver-typescript "^3.5.2" - eslint-plugin-import "^2.28.1" - eslint-plugin-jsx-a11y "^6.7.1" - eslint-plugin-react "^7.33.2" - eslint-plugin-react-hooks "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + eslint-plugin-import "^2.31.0" + eslint-plugin-jsx-a11y "^6.10.0" + eslint-plugin-react "^7.35.0" + eslint-plugin-react-hooks "^5.0.0" eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" @@ -1486,17 +1650,17 @@ eslint-import-resolver-typescript@^3.5.2: is-bun-module "^1.0.2" is-glob "^4.0.3" -eslint-module-utils@^2.8.1, eslint-module-utils@^2.9.0: +eslint-module-utils@^2.12.0, eslint-module-utils@^2.8.1: version "2.12.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" -eslint-plugin-import@^2.28.1: - version "2.30.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz#21ceea0fc462657195989dd780e50c92fe95f449" - integrity sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw== +eslint-plugin-import@^2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== dependencies: "@rtsao/scc" "^1.1.0" array-includes "^3.1.8" @@ -1506,7 +1670,7 @@ eslint-plugin-import@^2.28.1: debug "^3.2.7" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.9.0" + eslint-module-utils "^2.12.0" hasown "^2.0.2" is-core-module "^2.15.1" is-glob "^4.0.3" @@ -1515,9 +1679,10 @@ eslint-plugin-import@^2.28.1: object.groupby "^1.0.3" object.values "^1.2.0" semver "^6.3.1" + string.prototype.trimend "^1.0.8" tsconfig-paths "^3.15.0" -eslint-plugin-jsx-a11y@^6.7.1: +eslint-plugin-jsx-a11y@^6.10.0: version "6.10.0" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz#36fb9dead91cafd085ddbe3829602fb10ef28339" integrity sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg== @@ -1539,15 +1704,15 @@ eslint-plugin-jsx-a11y@^6.7.1: safe-regex-test "^1.0.3" string.prototype.includes "^2.0.0" -"eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": - version "4.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" - integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== +eslint-plugin-react-hooks@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz#72e2eefbac4b694f5324154619fee44f5f60f101" + integrity sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw== -eslint-plugin-react@^7.33.2: - version "7.36.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz#f1dabbb11f3d4ebe8b0cf4e54aff4aee81144ee5" - integrity sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA== +eslint-plugin-react@^7.35.0: + version "7.37.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz#56493d7d69174d0d828bc83afeffe96903fdadbd" + integrity sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg== dependencies: array-includes "^3.1.8" array.prototype.findlast "^1.2.5" @@ -1663,7 +1828,18 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2: +fast-glob@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-glob@^3.3.0, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -1852,23 +2028,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - -glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^10.3.10: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" @@ -1913,18 +2072,6 @@ globalthis@^1.0.3: define-properties "^1.2.1" gopd "^1.0.1" -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - goober@^2.0.33: version "2.1.14" resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.14.tgz#4a5c94fc34dc086a8e6035360ae1800005135acd" @@ -1937,7 +2084,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.2, graceful-fs@^4.2.4: +graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -2026,7 +2173,7 @@ hermes-parser@^0.22.0: dependencies: hermes-estree "0.22.0" -ignore@^5.2.0: +ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -2089,6 +2236,11 @@ is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: call-bind "^1.0.2" get-intrinsic "^1.2.1" +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-async-function@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" @@ -2438,7 +2590,7 @@ lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -2462,7 +2614,7 @@ lz-string@^1.5.0: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -2487,14 +2639,7 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -2554,28 +2699,28 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@^13.5.6: - version "13.5.7" - resolved "https://registry.yarnpkg.com/next/-/next-13.5.7.tgz#deddbb6644b235f0f6be2bbb6facce9ce004fd8e" - integrity sha512-W7KIRTE+hPcgGdq89P3mQLDX3m7pJ6nxSyC+YxYaUExE+cS4UledB+Ntk98tKoyhsv6fjb2TRAnD7VDvoqmeFg== +next@15.0.0-canary.197: + version "15.0.0-canary.197" + resolved "https://registry.yarnpkg.com/next/-/next-15.0.0-canary.197.tgz#0b7cf8b6a4a2ba6ca58712ed80709766160510aa" + integrity sha512-13rOJn7FPGmPt+ahDbbiAkJr1qharRbVJVU/pce+T+OGAbZ2kGu0DilJHFYOLEdlmb80+pO+UFHhcMRV4rVm7w== dependencies: - "@next/env" "13.5.7" - "@swc/helpers" "0.5.2" + "@next/env" "15.0.0-canary.197" + "@swc/counter" "0.1.3" + "@swc/helpers" "0.5.13" busboy "1.6.0" - caniuse-lite "^1.0.30001406" + caniuse-lite "^1.0.30001579" postcss "8.4.31" - styled-jsx "5.1.1" - watchpack "2.4.0" + styled-jsx "5.1.6" optionalDependencies: - "@next/swc-darwin-arm64" "13.5.7" - "@next/swc-darwin-x64" "13.5.7" - "@next/swc-linux-arm64-gnu" "13.5.7" - "@next/swc-linux-arm64-musl" "13.5.7" - "@next/swc-linux-x64-gnu" "13.5.7" - "@next/swc-linux-x64-musl" "13.5.7" - "@next/swc-win32-arm64-msvc" "13.5.7" - "@next/swc-win32-ia32-msvc" "13.5.7" - "@next/swc-win32-x64-msvc" "13.5.7" + "@next/swc-darwin-arm64" "15.0.0-canary.197" + "@next/swc-darwin-x64" "15.0.0-canary.197" + "@next/swc-linux-arm64-gnu" "15.0.0-canary.197" + "@next/swc-linux-arm64-musl" "15.0.0-canary.197" + "@next/swc-linux-x64-gnu" "15.0.0-canary.197" + "@next/swc-linux-x64-musl" "15.0.0-canary.197" + "@next/swc-win32-arm64-msvc" "15.0.0-canary.197" + "@next/swc-win32-x64-msvc" "15.0.0-canary.197" + sharp "^0.33.5" node-releases@^2.0.18: version "2.0.18" @@ -2748,11 +2893,6 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" @@ -2902,18 +3042,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-compiler-runtime@*: - version "0.0.0" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-0.0.0.tgz#906990637c0f367f836746931f4824b2acf8a05c" - integrity sha512-ZaNBKRbqg6eZc+YKtJ3MeOwUJ/XjBnEzYnUURWTcvOFGlA79g45QFj7bbVP2ITeUPkiY2PsZZu+NmFEje4p0RA== - -react-dom@18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== +react-dom@19.0.0-rc-77b637d6-20241016: + version "19.0.0-rc-77b637d6-20241016" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-rc-77b637d6-20241016.tgz#71afcba4abbd81a73e85086029202423cf85355e" + integrity sha512-xp5LvY+O6uvg0fNbSMyMXe0kbgzw6qn0mbqrdXStm4LBpFeMswLZ+XSNr+eJ0HyIiWrCw0rrXaVdqOxc9wtdKA== dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" + scheduler "0.25.0-rc-77b637d6-20241016" react-is@^16.13.1: version "16.13.1" @@ -2925,12 +3059,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@18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" +react@19.0.0-rc-77b637d6-20241016: + version "19.0.0-rc-77b637d6-20241016" + resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-rc-77b637d6-20241016.tgz#9e20f116d0195979f192537e00a0fa1687680319" + integrity sha512-9A+i+PGSH/P4MezU4w38K9cbJuy0pzsXoPjPWIv6TQGCFmc5qCzC+8yce8dzfSEF1KJgCF2CLc5qtq/ePfiVqg== read-cache@^1.0.0: version "1.0.0" @@ -3052,19 +3184,17 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" +scheduler@0.25.0-rc-77b637d6-20241016: + version "0.25.0-rc-77b637d6-20241016" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-rc-77b637d6-20241016.tgz#ab8f8d1cccc9668946caaa1103acdcdb5c871122" + integrity sha512-R5NTrZXJaW4Dj2jHmad2MTehpFq4yUQOxRKDNV7clP1q4Pz6RtUIcofdPnGUWM0krlJAw8DHd/4jT41pFK4iEg== semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.4, semver@^7.6.3: +semver@^7.6.0, semver@^7.6.3: version "7.6.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -3091,6 +3221,35 @@ set-function-name@^2.0.1, set-function-name@^2.0.2: functions-have-names "^1.2.3" has-property-descriptors "^1.0.2" +sharp@^0.33.5: + version "0.33.5" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.33.5.tgz#13e0e4130cc309d6a9497596715240b2ec0c594e" + integrity sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw== + dependencies: + color "^4.2.3" + detect-libc "^2.0.3" + semver "^7.6.3" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.33.5" + "@img/sharp-darwin-x64" "0.33.5" + "@img/sharp-libvips-darwin-arm64" "1.0.4" + "@img/sharp-libvips-darwin-x64" "1.0.4" + "@img/sharp-libvips-linux-arm" "1.0.5" + "@img/sharp-libvips-linux-arm64" "1.0.4" + "@img/sharp-libvips-linux-s390x" "1.0.4" + "@img/sharp-libvips-linux-x64" "1.0.4" + "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" + "@img/sharp-libvips-linuxmusl-x64" "1.0.4" + "@img/sharp-linux-arm" "0.33.5" + "@img/sharp-linux-arm64" "0.33.5" + "@img/sharp-linux-s390x" "0.33.5" + "@img/sharp-linux-x64" "0.33.5" + "@img/sharp-linuxmusl-arm64" "0.33.5" + "@img/sharp-linuxmusl-x64" "0.33.5" + "@img/sharp-wasm32" "0.33.5" + "@img/sharp-win32-ia32" "0.33.5" + "@img/sharp-win32-x64" "0.33.5" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3123,10 +3282,12 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" source-map-js@^1.0.2, source-map-js@^1.2.1: version "1.2.1" @@ -3275,10 +3436,10 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -styled-jsx@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" - integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== +styled-jsx@5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499" + integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== dependencies: client-only "0.0.1" @@ -3390,7 +3551,7 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -ts-api-utils@^1.0.1: +ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== @@ -3512,14 +3673,6 @@ wait-on@^7.2.0: minimist "^1.2.8" rxjs "^7.8.1" -watchpack@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" From 61383303d38d8b0c23b700e8c0a7d3b6fd51847e Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 14:09:30 -0400 Subject: [PATCH 297/426] [playground] Remove unnecessary fs package (#31292) Seems like this was accidentally added. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31292). * #31293 * __->__ #31292 * #31291 --- compiler/apps/playground/package.json | 1 - compiler/apps/playground/yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index 95fc72fd20a7d..57f04d3e78fcb 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -28,7 +28,6 @@ "@monaco-editor/react": "^4.4.6", "@playwright/test": "^1.42.1", "@use-gesture/react": "^10.2.22", - "fs": "^0.0.1-security", "hermes-eslint": "^0.14.0", "hermes-parser": "^0.22.0", "invariant": "^2.2.4", diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index 493ba6fbf9ad7..c85afb2986be9 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -1942,11 +1942,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fs@^0.0.1-security: - version "0.0.1-security" - resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" - integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== - fsevents@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" From 915be0ef783fa1891f2627e58b2ae2a22d44b4c3 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 14:25:36 -0400 Subject: [PATCH 298/426] [playground] Upgrade various packages (#31293) Just some housekeeping --- .github/workflows/compiler_playground.yml | 5 ++ .../playground/__tests__/e2e/page.spec.ts | 4 +- compiler/apps/playground/package.json | 7 ++- compiler/apps/playground/yarn.lock | 50 +++++++------------ 4 files changed, 29 insertions(+), 37 deletions(-) diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index 338a95d208a9b..a8a861923f04e 100644 --- a/.github/workflows/compiler_playground.yml +++ b/.github/workflows/compiler_playground.yml @@ -45,3 +45,8 @@ jobs: run: yarn install --frozen-lockfile - run: npx playwright install --with-deps chromium - run: yarn test + - name: Archive test results + uses: actions/upload-artifact@v4 + with: + name: test-results + path: test-results diff --git a/compiler/apps/playground/__tests__/e2e/page.spec.ts b/compiler/apps/playground/__tests__/e2e/page.spec.ts index bc93352a0992a..bc6083f52dc00 100644 --- a/compiler/apps/playground/__tests__/e2e/page.spec.ts +++ b/compiler/apps/playground/__tests__/e2e/page.spec.ts @@ -33,7 +33,7 @@ test('editor should compile successfully', async ({page}) => { path: 'test-results/01-show-js-before.png', }); const userInput = - (await page.locator('.monaco-editor').nth(2).allInnerTexts()) ?? []; + (await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? []; expect(concat(userInput)).toMatchSnapshot('user-input.txt'); // Reset button works @@ -44,6 +44,6 @@ test('editor should compile successfully', async ({page}) => { path: 'test-results/02-show-js-after.png', }); const defaultInput = - (await page.locator('.monaco-editor').nth(2).allInnerTexts()) ?? []; + (await page.locator('.monaco-editor').nth(1).allInnerTexts()) ?? []; expect(concat(defaultInput)).toMatchSnapshot('default-input.txt'); }); diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index 57f04d3e78fcb..bfdd799d21a59 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -28,11 +28,11 @@ "@monaco-editor/react": "^4.4.6", "@playwright/test": "^1.42.1", "@use-gesture/react": "^10.2.22", - "hermes-eslint": "^0.14.0", - "hermes-parser": "^0.22.0", + "hermes-eslint": "^0.25.0", + "hermes-parser": "^0.25.0", "invariant": "^2.2.4", "lz-string": "^1.5.0", - "monaco-editor": "^0.34.1", + "monaco-editor": "^0.52.0", "next": "15.0.0-canary.197", "notistack": "^3.0.0-alpha.7", "prettier": "^3.3.3", @@ -50,7 +50,6 @@ "concurrently": "^7.4.0", "eslint": "^8.28.0", "eslint-config-next": "15.0.0-canary.197", - "hermes-parser": "^0.22.0", "monaco-editor-webpack-plugin": "^7.1.0", "postcss": "^8.4.31", "tailwindcss": "^3.2.4", diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index c85afb2986be9..2abe56e8a423c 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -2135,38 +2135,26 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" -hermes-eslint@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.14.0.tgz#d56426b0931a7ced99d08b4b6a06f798064b13ba" - integrity sha512-ORk7znDabvALzTbI3QRIQefCkxF1ukDm3dVut3e+cVmwdtsTC71BJetSvdh1jtgK10czwck1QiPZOVOVolhiqQ== +hermes-eslint@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/hermes-eslint/-/hermes-eslint-0.25.0.tgz#beec5f0d9e9e9bdef9e4a420a79038ca7fe84143" + integrity sha512-D9rdrqt7dudZHI5AJKS+1vXBbxxR6Wj9J1JI7eYowYCbXUIvHclsWFy8gSuRmug2V6HSYpsiyPwP3kQs/Q/Y8w== dependencies: esrecurse "^4.3.0" - hermes-estree "0.14.0" - hermes-parser "0.14.0" + hermes-estree "0.25.0" + hermes-parser "0.25.0" -hermes-estree@0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.14.0.tgz#c663eea1400980802283338a09d0087c448729e7" - integrity sha512-L6M67+0/eSEbt6Ha2XOBFXL++7MR34EOJMgm+j7YCaI4L/jZqrVAg6zYQKzbs1ZCFDLvEQpOgLlapTX4gpFriA== +hermes-estree@0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.0.tgz#fd926ebf3d0d3441a934f19ef3d3d3d4145b1d71" + integrity sha512-xjILoUIyOpLoOHqj8UJs/HNYQ279IfLKTTv9nmXKNT2+QKT/TQF9AyQFrRMo+3xwZoO7k4azocYpCzA1cSvBDg== -hermes-estree@0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.22.0.tgz#38559502b119f728901d2cfe2ef422f277802a1d" - integrity sha512-FLBt5X9OfA8BERUdc6aZS36Xz3rRuB0Y/mfocSADWEJfomc1xfene33GdyAmtTkKTBXTN/EgAy+rjTKkkZJHlw== - -hermes-parser@0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.14.0.tgz#edb2e7172fce996d2c8bbba250d140b70cc1aaaf" - integrity sha512-pt+8uRiJhVlErY3fiXB3gKhZ72RxM6E1xRMpvfZ5n6Z5TQKQQXKorgRCRzoe02mmvLKBJFP5nPDGv75MWAgCTw== - dependencies: - hermes-estree "0.14.0" - -hermes-parser@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.22.0.tgz#fc8e0e6c7bfa8db85b04c9f9544a102c4fcb4040" - integrity sha512-gn5RfZiEXCsIWsFGsKiykekktUoh0PdFWYocXsUdZIyWSckT6UIyPcyyUIPSR3kpnELWeK3n3ztAse7Mat6PSA== +hermes-parser@0.25.0, hermes-parser@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.0.tgz#634934533a956e392ae0988421e4b0315e30351e" + integrity sha512-CeAdhgMfbZcrYh+HHKVKsj7VNhOTr0jiLFlcVVoRORbZ/Nr4J90WjEq2CZoahgH15/DYY/VBhuLqpIzJqfdBEQ== dependencies: - hermes-estree "0.22.0" + hermes-estree "0.25.0" ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" @@ -2665,10 +2653,10 @@ monaco-editor-webpack-plugin@^7.1.0: dependencies: loader-utils "^2.0.2" -monaco-editor@^0.34.1: - version "0.34.1" - resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.34.1.tgz#1b75c4ad6bc4c1f9da656d740d98e0b850a22f87" - integrity sha512-FKc80TyiMaruhJKKPz5SpJPIjL+dflGvz4CpuThaPMc94AyN7SeC9HQ8hrvaxX7EyHdJcUY5i4D0gNyJj1vSZQ== +monaco-editor@^0.52.0: + version "0.52.0" + resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.52.0.tgz#d47c02b191eae208d68878d679b3ee7456031be7" + integrity sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw== ms@^2.1.1, ms@^2.1.3: version "2.1.3" From cdde15efe189e8bebe227b7555e7cc95ad74deab Mon Sep 17 00:00:00 2001 From: Joseph Savona <6425824+josephsavona@users.noreply.github.com> Date: Fri, 18 Oct 2024 11:27:48 -0700 Subject: [PATCH 299/426] [compiler] InlineJSXTransform transforms jsx inside function expressions (#31282) InlineJSXTransform wasn't traversing into function expressions or object methods, so any JSX inside such functions wouldn't have gotten inlined. This PR updates to traverse nested functions to transform all JSX within a hook or component. Note that this still doesn't transform JSX outside of components or hooks, ie in standalone render helpers. --- .../src/Optimization/InlineJsxTransform.ts | 11 +++ .../compiler/inline-jsx-transform.expect.md | 96 +++++++++++++------ .../fixtures/compiler/inline-jsx-transform.js | 10 +- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 396e6ad1be8dc..89efa78469786 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -405,6 +405,17 @@ export function inlineJsxTransform( nextInstructions.push(reactElementInstruction); break; } + case 'FunctionExpression': + case 'ObjectMethod': { + inlineJsxTransform( + instr.value.loweredFunc.func, + inlineJsxTransformConfig, + ); + if (nextInstructions !== null) { + nextInstructions.push(instr); + } + break; + } default: { if (nextInstructions !== null) { nextInstructions.push(instr); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md index 6dd899d5c7408..2078575e83e8a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -26,11 +26,15 @@ function ParentAndRefAndKey(props) { } function ParentAndChildren(props) { + const render = () => { + return
{props.foo}
; + }; return ( - + + {render()} ); @@ -40,8 +44,8 @@ const propsToSpread = {a: 'a', b: 'b', c: 'c'}; function PropsSpread() { return ( <> - - + + ); } @@ -151,37 +155,30 @@ function ParentAndRefAndKey(props) { } function ParentAndChildren(props) { - const $ = _c2(7); + const $ = _c2(14); let t0; - if ($[0] !== props) { - t0 = { + if ($[0] !== props.foo) { + t0 = () => ({ $$typeof: Symbol.for("react.transitional.element"), - type: Child, + type: "div", ref: null, - key: "a", - props: props, - }; - $[0] = props; + key: "d", + props: { children: props.foo }, + }); + $[0] = props.foo; $[1] = t0; } else { t0 = $[1]; } + const render = t0; let t1; if ($[2] !== props) { t1 = { $$typeof: Symbol.for("react.transitional.element"), type: Child, ref: null, - key: "b", - props: { - children: { - $$typeof: Symbol.for("react.transitional.element"), - type: GrandChild, - ref: null, - key: null, - props: { className: props.foo, ...props }, - }, - }, + key: "a", + props: props, }; $[2] = props; $[3] = t1; @@ -189,21 +186,58 @@ function ParentAndChildren(props) { t1 = $[3]; } let t2; - if ($[4] !== t0 || $[5] !== t1) { + if ($[4] !== props) { t2 = { + $$typeof: Symbol.for("react.transitional.element"), + type: GrandChild, + ref: null, + key: "c", + props: { className: props.foo, ...props }, + }; + $[4] = props; + $[5] = t2; + } else { + t2 = $[5]; + } + let t3; + if ($[6] !== render) { + t3 = render(); + $[6] = render; + $[7] = t3; + } else { + t3 = $[7]; + } + let t4; + if ($[8] !== t2 || $[9] !== t3) { + t4 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Child, + ref: null, + key: "b", + props: { children: [t2, t3] }, + }; + $[8] = t2; + $[9] = t3; + $[10] = t4; + } else { + t4 = $[10]; + } + let t5; + if ($[11] !== t1 || $[12] !== t4) { + t5 = { $$typeof: Symbol.for("react.transitional.element"), type: Parent, ref: null, key: null, - props: { children: [t0, t1] }, + props: { children: [t1, t4] }, }; - $[4] = t0; - $[5] = t1; - $[6] = t2; + $[11] = t1; + $[12] = t4; + $[13] = t5; } else { - t2 = $[6]; + t5 = $[13]; } - return t2; + return t5; } const propsToSpread = { a: "a", b: "b", c: "c" }; @@ -222,14 +256,14 @@ function PropsSpread() { $$typeof: Symbol.for("react.transitional.element"), type: Test, ref: null, - key: null, + key: "a", props: propsToSpread, }, { $$typeof: Symbol.for("react.transitional.element"), type: Test, ref: null, - key: null, + key: "b", props: { ...propsToSpread, a: "z" }, }, ], @@ -250,4 +284,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: ok)
Hello world
\ No newline at end of file +(kind: ok)
Hello world
abc
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js index 4a9d53b6f4b96..6fe9553dcd5a1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js @@ -22,11 +22,15 @@ function ParentAndRefAndKey(props) { } function ParentAndChildren(props) { + const render = () => { + return
{props.foo}
; + }; return ( - + + {render()} ); @@ -36,8 +40,8 @@ const propsToSpread = {a: 'a', b: 'b', c: 'c'}; function PropsSpread() { return ( <> - - + + ); } From 9deb36748d699bd33f9041db5559c451c54e77a9 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 14:43:43 -0400 Subject: [PATCH 300/426] [ci] Publish compiler weekly prereleases (#31294) Adds a new weekly job for the compiler --- .../workflows/compiler_prereleases_weekly.yml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/compiler_prereleases_weekly.yml diff --git a/.github/workflows/compiler_prereleases_weekly.yml b/.github/workflows/compiler_prereleases_weekly.yml new file mode 100644 index 0000000000000..79a9451b6972a --- /dev/null +++ b/.github/workflows/compiler_prereleases_weekly.yml @@ -0,0 +1,21 @@ +name: (Compiler) Publish Prereleases Weekly + +on: + schedule: + # At 10 minutes past 9:00 on Mon + - cron: 10 9 * * 1 + +env: + TZ: /usr/share/zoneinfo/America/Los_Angeles + +jobs: + publish_prerelease_beta: + name: Publish to beta channel + uses: facebook/react/.github/workflows/compiler_prereleases.yml@main + with: + commit_sha: ${{ github.sha }} + release_channel: beta + dist_tag: beta + version_name: '19.0.0' + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} From 54c0edc019b97d8c08b8c2ccb552da4e5ea8a8cd Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 15:02:14 -0400 Subject: [PATCH 301/426] [ci] Don't use branch name for concurrency (#31296) I happened to notice some jobs on main get canceled if another PR landed before the prior commit on main had finished running CI. This is not great for difftrain because the commit artifacts job relies on the CI jobs on main finishing before it triggers. This would lead to commits being skipped on DiffTrain which is not great for provenance since we want it to be a 1:1 sync. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31296). * #31297 * __->__ #31296 --- .github/workflows/compiler_playground.yml | 2 +- .github/workflows/compiler_rust.yml | 2 +- .github/workflows/compiler_typescript.yml | 2 +- .github/workflows/runtime_build_and_test.yml | 2 +- .github/workflows/shared_lint.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index a8a861923f04e..0d4c4d2726cc1 100644 --- a/.github/workflows/compiler_playground.yml +++ b/.github/workflows/compiler_playground.yml @@ -9,7 +9,7 @@ on: - .github/workflows/compiler-playground.yml concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true env: diff --git a/.github/workflows/compiler_rust.yml b/.github/workflows/compiler_rust.yml index 6b4a023a298a0..50d42a37763e3 100644 --- a/.github/workflows/compiler_rust.yml +++ b/.github/workflows/compiler_rust.yml @@ -16,7 +16,7 @@ on: - compiler/*.toml concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true env: diff --git a/.github/workflows/compiler_typescript.yml b/.github/workflows/compiler_typescript.yml index acd23eeb956c2..7ec6297038479 100644 --- a/.github/workflows/compiler_typescript.yml +++ b/.github/workflows/compiler_typescript.yml @@ -9,7 +9,7 @@ on: - .github/workflows/compiler_typescript.yml concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true env: diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index 1a85eb408461b..c59d990ba0ced 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -8,7 +8,7 @@ on: - compiler/** concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true env: diff --git a/.github/workflows/shared_lint.yml b/.github/workflows/shared_lint.yml index a3608ec291e63..00155e8e55976 100644 --- a/.github/workflows/shared_lint.yml +++ b/.github/workflows/shared_lint.yml @@ -6,7 +6,7 @@ on: pull_request: concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true env: From 1839e1437f652819682f2c7970687ac19e551534 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 15:02:26 -0400 Subject: [PATCH 302/426] [ez] Update compiler issue template (#31297) Add a field to specify which version of React Compiler is being used. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31297). * __->__ #31297 * #31296 --- .github/ISSUE_TEMPLATE/compiler_bug_report.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/compiler_bug_report.yml b/.github/ISSUE_TEMPLATE/compiler_bug_report.yml index fc7952fd5a80f..233201d3f5b1a 100644 --- a/.github/ISSUE_TEMPLATE/compiler_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/compiler_bug_report.yml @@ -55,3 +55,10 @@ body: Please provide your React version in the app where this issue occurred. validations: required: true +- type: input + attributes: + label: What version of React Compiler are you using? + description: | + Please provide the exact React Compiler version in the app where this issue occurred. + validations: + required: true From 39a7730b1311fb78642c36686820d8d1c79e58e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sat, 19 Oct 2024 20:45:20 -0400 Subject: [PATCH 303/426] Rename SSRManifest to ServerConsumerManifest (#31299) This config is more generally applicable to all server-side Flight Clients and not just SSR. --- fixtures/flight/server/global.js | 12 ++++-- .../react-client/src/ReactFlightClient.js | 8 ++-- .../forks/ReactFlightClientConfig.custom.js | 2 +- .../forks/ReactFlightClientConfig.dom-bun.js | 2 +- .../ReactFlightClientConfig.dom-legacy.js | 2 +- .../forks/ReactFlightClientConfig.markup.js | 4 +- .../ReactFlightClientConfigBundlerESM.js | 4 +- .../ReactFlightTurbopackDOMEdge-test.js | 2 +- .../ReactFlightClientConfigBundlerNode.js | 4 +- ...ReactFlightClientConfigBundlerTurbopack.js | 4 +- .../src/client/ReactFlightDOMClientEdge.js | 12 +++--- .../src/client/ReactFlightDOMClientNode.js | 12 +++--- .../src/ReactFlightWebpackPlugin.js | 16 +++---- .../src/__tests__/ReactFlightDOMEdge-test.js | 36 ++++++++-------- .../src/__tests__/ReactFlightDOMForm-test.js | 42 +++++++++---------- .../src/__tests__/ReactFlightDOMNode-test.js | 12 +++--- .../ReactFlightClientConfigBundlerNode.js | 4 +- .../ReactFlightClientConfigBundlerWebpack.js | 4 +- .../src/client/ReactFlightDOMClientEdge.js | 12 +++--- .../src/client/ReactFlightDOMClientNode.js | 12 +++--- 20 files changed, 106 insertions(+), 100 deletions(-) diff --git a/fixtures/flight/server/global.js b/fixtures/flight/server/global.js index 8133bf7912199..a2fa737ae0f4d 100644 --- a/fixtures/flight/server/global.js +++ b/fixtures/flight/server/global.js @@ -130,7 +130,7 @@ async function renderApp(req, res, next) { buildPath = path.join(__dirname, '../build/'); } // Read the module map from the virtual file system. - const ssrManifest = JSON.parse( + const serverConsumerManifest = JSON.parse( await virtualFs.readFile( path.join(buildPath, 'react-ssr-manifest.json'), 'utf8' @@ -160,14 +160,20 @@ async function renderApp(req, res, next) { rscResponse.pipe(rscResponse1); rscResponse.pipe(rscResponse2); - const {formState} = await createFromNodeStream(rscResponse1, ssrManifest); + const {formState} = await createFromNodeStream( + rscResponse1, + serverConsumerManifest + ); rscResponse1.end(); let cachedResult; let Root = () => { if (!cachedResult) { // Read this stream inside the render. - cachedResult = createFromNodeStream(rscResponse2, ssrManifest); + cachedResult = createFromNodeStream( + rscResponse2, + serverConsumerManifest + ); } return React.use(cachedResult).root; }; diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 2a6165c932a16..bc8704d8d1a56 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -20,7 +20,7 @@ import type {LazyComponent} from 'react/src/ReactLazy'; import type { ClientReference, ClientReferenceMetadata, - SSRModuleMap, + ServerConsumerModuleMap, StringDecoder, ModuleLoading, } from './ReactFlightClientConfig'; @@ -269,7 +269,7 @@ export type FindSourceMapURLCallback = ( ) => null | string; export type Response = { - _bundlerConfig: SSRModuleMap, + _bundlerConfig: ServerConsumerModuleMap, _moduleLoading: ModuleLoading, _callServer: CallServerCallback, _encodeFormAction: void | EncodeFormActionCallback, @@ -1420,7 +1420,7 @@ function missingCall() { function ResponseInstance( this: $FlowFixMe, - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, moduleLoading: ModuleLoading, callServer: void | CallServerCallback, encodeFormAction: void | EncodeFormActionCallback, @@ -1485,7 +1485,7 @@ function ResponseInstance( } export function createResponse( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, moduleLoading: ModuleLoading, callServer: void | CallServerCallback, encodeFormAction: void | EncodeFormActionCallback, diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.custom.js b/packages/react-client/src/forks/ReactFlightClientConfig.custom.js index 530d548a590d0..2f204fd51b098 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.custom.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.custom.js @@ -26,7 +26,7 @@ declare const $$$config: any; export opaque type ModuleLoading = mixed; -export opaque type SSRModuleMap = mixed; +export opaque type ServerConsumerModuleMap = mixed; export opaque type ServerManifest = mixed; export opaque type ServerReferenceId = string; export opaque type ClientReferenceMetadata = mixed; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js index 7b75983cdd728..75c942966bd99 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-bun.js @@ -15,7 +15,7 @@ export * from 'react-client/src/ReactClientConsoleConfigPlain'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export opaque type ModuleLoading = mixed; -export opaque type SSRModuleMap = mixed; +export opaque type ServerConsumerModuleMap = mixed; export opaque type ServerManifest = mixed; export opaque type ServerReferenceId = string; export opaque type ClientReferenceMetadata = mixed; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js b/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js index 05e937abdf82e..5be648ff0ad93 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.dom-legacy.js @@ -15,7 +15,7 @@ export * from 'react-client/src/ReactClientConsoleConfigBrowser'; export type Response = any; export opaque type ModuleLoading = mixed; -export opaque type SSRModuleMap = mixed; +export opaque type ServerConsumerModuleMap = mixed; export opaque type ServerManifest = mixed; export opaque type ServerReferenceId = string; export opaque type ClientReferenceMetadata = mixed; diff --git a/packages/react-client/src/forks/ReactFlightClientConfig.markup.js b/packages/react-client/src/forks/ReactFlightClientConfig.markup.js index ba86f7631ffce..b0b2f198fd97b 100644 --- a/packages/react-client/src/forks/ReactFlightClientConfig.markup.js +++ b/packages/react-client/src/forks/ReactFlightClientConfig.markup.js @@ -16,7 +16,7 @@ export * from 'react-markup/src/ReactMarkupLegacyClientStreamConfig.js'; export * from 'react-client/src/ReactClientConsoleConfigPlain'; export type ModuleLoading = null; -export type SSRModuleMap = null; +export type ServerConsumerModuleMap = null; export opaque type ServerManifest = null; export opaque type ServerReferenceId = string; export opaque type ClientReferenceMetadata = null; @@ -33,7 +33,7 @@ export function prepareDestinationForModule( } export function resolveClientReference( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, metadata: ClientReferenceMetadata, ): ClientReference { throw new Error( diff --git a/packages/react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM.js b/packages/react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM.js index 5db99dc8fff05..6a74e63854991 100644 --- a/packages/react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM.js +++ b/packages/react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM.js @@ -14,7 +14,7 @@ import type { } from 'shared/ReactTypes'; import type {ModuleLoading} from 'react-client/src/ReactFlightClientConfig'; -export type SSRModuleMap = string; // Module root path +export type ServerConsumerModuleMap = string; // Module root path export type ServerManifest = string; // Module root path @@ -48,7 +48,7 @@ export function prepareDestinationForModule( } export function resolveClientReference( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, metadata: ClientReferenceMetadata, ): ClientReference { const baseURL = bundlerConfig; diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js index 767e1f1ed0ebc..5e4fd2cdd5bd9 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js @@ -97,7 +97,7 @@ describe('ReactFlightTurbopackDOMEdge', () => { turbopackMap, ); const response = ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverManifest: { moduleMap: translationMap, moduleLoading: null, }, diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js index 36832c47e39ec..22321d41d0824 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js @@ -24,7 +24,7 @@ import { } from '../shared/ReactFlightImportMetadata'; import {prepareDestinationWithChunks} from 'react-client/src/ReactFlightClientConfig'; -export type SSRModuleMap = { +export type ServerConsumerModuleMap = { [clientId: string]: { [clientExportName: string]: ClientReference, }, @@ -58,7 +58,7 @@ export function prepareDestinationForModule( } export function resolveClientReference( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, metadata: ClientReferenceMetadata, ): ClientReference { const moduleExports = bundlerConfig[metadata[ID]]; diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js index 212970222080f..4ae4a3e365d0c 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js @@ -30,7 +30,7 @@ import {prepareDestinationWithChunks} from 'react-client/src/ReactFlightClientCo import {loadChunk} from 'react-client/src/ReactFlightClientConfig'; -export type SSRModuleMap = null | { +export type ServerConsumerModuleMap = null | { [clientId: string]: { [clientExportName: string]: ClientReferenceManifestEntry, }, @@ -63,7 +63,7 @@ export function prepareDestinationForModule( } export function resolveClientReference( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, metadata: ClientReferenceMetadata, ): ClientReference { if (bundlerConfig) { diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js index 956e014042733..f9ac4e9d257de 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js @@ -17,12 +17,12 @@ import type { import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient'; import type { - SSRModuleMap, + ServerConsumerModuleMap, ModuleLoading, } from 'react-client/src/ReactFlightClientConfig'; -type SSRManifest = { - moduleMap: SSRModuleMap, +type ServerConsumerManifest = { + moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, }; @@ -66,7 +66,7 @@ type EncodeFormActionCallback = ( ) => ReactCustomFormAction; export type Options = { - ssrManifest: SSRManifest, + serverManifest: ServerConsumerManifest, nonce?: string, encodeFormAction?: EncodeFormActionCallback, temporaryReferences?: TemporaryReferenceSet, @@ -77,8 +77,8 @@ export type Options = { function createResponseFromOptions(options: Options) { return createResponse( - options.ssrManifest.moduleMap, - options.ssrManifest.moduleLoading, + options.serverManifest.moduleMap, + options.serverManifest.moduleLoading, noServerCall, options.encodeFormAction, typeof options.nonce === 'string' ? options.nonce : undefined, diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js index d46364b7814e0..528df26f11f96 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js @@ -15,12 +15,12 @@ import type { } from 'react-client/src/ReactFlightClient'; import type { - SSRModuleMap, + ServerConsumerModuleMap, ModuleLoading, } from 'react-client/src/ReactFlightClientConfig'; -type SSRManifest = { - moduleMap: SSRModuleMap, +type ServerConsumerManifest = { + moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, }; @@ -66,12 +66,12 @@ export type Options = { function createFromNodeStream( stream: Readable, - ssrManifest: SSRManifest, + serverConsumerManifest: ServerConsumerManifest, options?: Options, ): Thenable { const response: Response = createResponse( - ssrManifest.moduleMap, - ssrManifest.moduleLoading, + serverConsumerManifest.moduleMap, + serverConsumerManifest.moduleLoading, noServerCall, options ? options.encodeFormAction : undefined, options && typeof options.nonce === 'string' ? options.nonce : undefined, diff --git a/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js b/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js index 82b866e419d49..816b9f2a73185 100644 --- a/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js +++ b/packages/react-server-dom-webpack/src/ReactFlightWebpackPlugin.js @@ -58,7 +58,7 @@ type Options = { clientReferences?: ClientReferencePath | $ReadOnlyArray, chunkName?: string, clientManifestFilename?: string, - ssrManifestFilename?: string, + serverConsumerManifestFilename?: string, }; const PLUGIN_NAME = 'React Server Plugin'; @@ -67,7 +67,7 @@ export default class ReactFlightWebpackPlugin { clientReferences: $ReadOnlyArray; chunkName: string; clientManifestFilename: string; - ssrManifestFilename: string; + serverConsumerManifestFilename: string; constructor(options: Options) { if (!options || typeof options.isServer !== 'boolean') { @@ -105,8 +105,8 @@ export default class ReactFlightWebpackPlugin { } this.clientManifestFilename = options.clientManifestFilename || 'react-client-manifest.json'; - this.ssrManifestFilename = - options.ssrManifestFilename || 'react-ssr-manifest.json'; + this.serverConsumerManifestFilename = + options.serverConsumerManifestFilename || 'react-ssr-manifest.json'; } apply(compiler: any) { @@ -239,18 +239,18 @@ export default class ReactFlightWebpackPlugin { const clientManifest: { [string]: ImportManifestEntry, } = {}; - type SSRModuleMap = { + type ServerConsumerModuleMap = { [string]: { [string]: {specifier: string, name: string}, }, }; - const moduleMap: SSRModuleMap = {}; + const moduleMap: ServerConsumerModuleMap = {}; const ssrBundleConfig: { moduleLoading: { prefix: string, crossOrigin: string | null, }, - moduleMap: SSRModuleMap, + moduleMap: ServerConsumerModuleMap, } = { moduleLoading: { prefix: compilation.outputOptions.publicPath || '', @@ -374,7 +374,7 @@ export default class ReactFlightWebpackPlugin { ); const ssrOutput = JSON.stringify(ssrBundleConfig, null, 2); compilation.emitAsset( - _this.ssrManifestFilename, + _this.serverConsumerManifestFilename, new sources.RawSource(ssrOutput, false), ); }, diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 27dbcc067e91a..41cffe84d249b 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -195,7 +195,7 @@ describe('ReactFlightDOMEdge', () => { ReactServerDOMServer.renderToReadableStream(, webpackMap), ); const response = ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: translationMap, moduleLoading: webpackModuleLoading, }, @@ -235,7 +235,7 @@ describe('ReactFlightDOMEdge', () => { const result = await ReactServerDOMClient.createFromReadableStream( stream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -263,7 +263,7 @@ describe('ReactFlightDOMEdge', () => { const result = await ReactServerDOMClient.createFromReadableStream( stream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -333,7 +333,7 @@ describe('ReactFlightDOMEdge', () => { expect(timesRendered).toBeLessThan(5); const model = await ReactServerDOMClient.createFromReadableStream(stream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -405,7 +405,7 @@ describe('ReactFlightDOMEdge', () => { const model = await serverAct(() => ReactServerDOMClient.createFromReadableStream(stream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -462,7 +462,7 @@ describe('ReactFlightDOMEdge', () => { passThrough(ReactServerDOMServer.renderToReadableStream(buffers)), ); const result = await ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -482,7 +482,7 @@ describe('ReactFlightDOMEdge', () => { passThrough(ReactServerDOMServer.renderToReadableStream(blob)), ); const result = await ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -512,7 +512,7 @@ describe('ReactFlightDOMEdge', () => { passThrough(ReactServerDOMServer.renderToReadableStream(formData)), ); const result = await ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -547,7 +547,7 @@ describe('ReactFlightDOMEdge', () => { const resultPromise = ReactServerDOMClient.createFromReadableStream( stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -587,7 +587,7 @@ describe('ReactFlightDOMEdge', () => { const result = await serverAct(() => ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -635,7 +635,7 @@ describe('ReactFlightDOMEdge', () => { // Parsing the root blocks because the module hasn't loaded yet const result = await serverAct(() => ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -689,7 +689,7 @@ describe('ReactFlightDOMEdge', () => { const result = await ReactServerDOMClient.createFromReadableStream( stream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -777,7 +777,7 @@ describe('ReactFlightDOMEdge', () => { const result = await ReactServerDOMClient.createFromReadableStream( stream1, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -836,7 +836,7 @@ describe('ReactFlightDOMEdge', () => { const result = await ReactServerDOMClient.createFromReadableStream( stream1, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -891,7 +891,7 @@ describe('ReactFlightDOMEdge', () => { const rootModel = await serverAct(() => ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -995,7 +995,7 @@ describe('ReactFlightDOMEdge', () => { const rootModel = await serverAct(() => ReactServerDOMClient.createFromReadableStream(stream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -1079,7 +1079,7 @@ describe('ReactFlightDOMEdge', () => { } const response = ReactServerDOMClient.createFromReadableStream(prelude, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -1146,7 +1146,7 @@ describe('ReactFlightDOMEdge', () => { } const response = ReactServerDOMClient.createFromReadableStream(prelude, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js index b2d13c7580985..b33e2a38ed305 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMForm-test.js @@ -166,7 +166,7 @@ describe('ReactFlightDOMForm', () => { } const rscStream = ReactServerDOMServer.renderToReadableStream(); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -232,7 +232,7 @@ describe('ReactFlightDOMForm', () => { } const rscStream = ReactServerDOMServer.renderToReadableStream(); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -272,7 +272,7 @@ describe('ReactFlightDOMForm', () => { } const rscStream = ReactServerDOMServer.renderToReadableStream(); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -343,7 +343,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -391,7 +391,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -444,7 +444,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -469,7 +469,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse = ReactServerDOMClient.createFromReadableStream( postbackRscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -539,7 +539,7 @@ describe('ReactFlightDOMForm', () => { const response = ReactServerDOMClient.createFromReadableStream( rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -569,7 +569,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse = ReactServerDOMClient.createFromReadableStream( postbackRscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -601,7 +601,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse2 = ReactServerDOMClient.createFromReadableStream( postbackRscStream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -660,7 +660,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -687,7 +687,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse = ReactServerDOMClient.createFromReadableStream( postbackRscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -738,7 +738,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -766,7 +766,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse = ReactServerDOMClient.createFromReadableStream( postbackRscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -794,7 +794,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse2 = ReactServerDOMClient.createFromReadableStream( postbackRscStream2, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -838,7 +838,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -891,7 +891,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -928,7 +928,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -954,7 +954,7 @@ describe('ReactFlightDOMForm', () => { const postbackResponse = ReactServerDOMClient.createFromReadableStream( postbackRscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -1007,7 +1007,7 @@ describe('ReactFlightDOMForm', () => { webpackMap, ); const response = ReactServerDOMClient.createFromReadableStream(rscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -1032,7 +1032,7 @@ describe('ReactFlightDOMForm', () => { ); const postbackResponse = await ReactServerDOMClient.createFromReadableStream(postbackRscStream, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js index f2dca4a45c7fa..6593044005083 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMNode-test.js @@ -130,7 +130,7 @@ describe('ReactFlightDOMNode', () => { '*': ssrMetadata, }, }; - const ssrManifest = { + const serverConsumerManifest = { moduleMap: translationMap, moduleLoading: webpackModuleLoading, }; @@ -151,7 +151,7 @@ describe('ReactFlightDOMNode', () => { if (response) return use(response); response = ReactServerDOMClient.createFromNodeStream( readable, - ssrManifest, + serverConsumerManifest, ); return use(response); } @@ -255,7 +255,7 @@ describe('ReactFlightDOMNode', () => { '*': ssrMetadata, }, }; - const ssrManifest = { + const serverConsumerManifest = { moduleMap: translationMap, moduleLoading: webpackModuleLoading, }; @@ -276,7 +276,7 @@ describe('ReactFlightDOMNode', () => { if (response) return use(response); response = ReactServerDOMClient.createFromNodeStream( readable, - ssrManifest, + serverConsumerManifest, { nonce: 'r4nd0m', }, @@ -426,7 +426,7 @@ describe('ReactFlightDOMNode', () => { } const response = ReactServerDOMClient.createFromNodeStream(prelude, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, @@ -492,7 +492,7 @@ describe('ReactFlightDOMNode', () => { } const response = ReactServerDOMClient.createFromNodeStream(prelude, { - ssrManifest: { + serverConsumerManifest: { moduleMap: null, moduleLoading: null, }, diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js index 36832c47e39ec..22321d41d0824 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js @@ -24,7 +24,7 @@ import { } from '../shared/ReactFlightImportMetadata'; import {prepareDestinationWithChunks} from 'react-client/src/ReactFlightClientConfig'; -export type SSRModuleMap = { +export type ServerConsumerModuleMap = { [clientId: string]: { [clientExportName: string]: ClientReference, }, @@ -58,7 +58,7 @@ export function prepareDestinationForModule( } export function resolveClientReference( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, metadata: ClientReferenceMetadata, ): ClientReference { const moduleExports = bundlerConfig[metadata[ID]]; diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js index de3afd6c4e8b4..521b19e5a7ad4 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js @@ -30,7 +30,7 @@ import {prepareDestinationWithChunks} from 'react-client/src/ReactFlightClientCo import {loadChunk} from 'react-client/src/ReactFlightClientConfig'; -export type SSRModuleMap = null | { +export type ServerConsumerModuleMap = null | { [clientId: string]: { [clientExportName: string]: ClientReferenceManifestEntry, }, @@ -63,7 +63,7 @@ export function prepareDestinationForModule( } export function resolveClientReference( - bundlerConfig: SSRModuleMap, + bundlerConfig: ServerConsumerModuleMap, metadata: ClientReferenceMetadata, ): ClientReference { if (bundlerConfig) { diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js index 956e014042733..23bd02af42a21 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js @@ -17,12 +17,12 @@ import type { import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient'; import type { - SSRModuleMap, + ServerConsumerModuleMap, ModuleLoading, } from 'react-client/src/ReactFlightClientConfig'; -type SSRManifest = { - moduleMap: SSRModuleMap, +type ServerConsumerManifest = { + moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, }; @@ -66,7 +66,7 @@ type EncodeFormActionCallback = ( ) => ReactCustomFormAction; export type Options = { - ssrManifest: SSRManifest, + serverConsumerManifest: ServerConsumerManifest, nonce?: string, encodeFormAction?: EncodeFormActionCallback, temporaryReferences?: TemporaryReferenceSet, @@ -77,8 +77,8 @@ export type Options = { function createResponseFromOptions(options: Options) { return createResponse( - options.ssrManifest.moduleMap, - options.ssrManifest.moduleLoading, + options.serverConsumerManifest.moduleMap, + options.serverConsumerManifest.moduleLoading, noServerCall, options.encodeFormAction, typeof options.nonce === 'string' ? options.nonce : undefined, diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js index 25e94b2f8f83f..eab37b3bce924 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js @@ -15,12 +15,12 @@ import type { } from 'react-client/src/ReactFlightClient'; import type { - SSRModuleMap, + ServerConsumerModuleMap, ModuleLoading, } from 'react-client/src/ReactFlightClientConfig'; -type SSRManifest = { - moduleMap: SSRModuleMap, +type ServerConsumerManifest = { + moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, }; @@ -67,12 +67,12 @@ export type Options = { function createFromNodeStream( stream: Readable, - ssrManifest: SSRManifest, + serverConsumerManifest: ServerConsumerManifest, options?: Options, ): Thenable { const response: Response = createResponse( - ssrManifest.moduleMap, - ssrManifest.moduleLoading, + serverConsumerManifest.moduleMap, + serverConsumerManifest.moduleLoading, noServerCall, options ? options.encodeFormAction : undefined, options && typeof options.nonce === 'string' ? options.nonce : undefined, From 22b2b1a05a86f599d2eea9d0419ac57db510e134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sat, 19 Oct 2024 21:10:25 -0400 Subject: [PATCH 304/426] [Flight] Add serverModuleMap option for mapping ServerReferences (#31300) Stacked on #31299. We already have an option for resolving Client References to other Client References when consuming an RSC payload on the server. This lets you resolve Server References on the consuming side when the environment where you're consuming the RSC payload also has access to those Server References. Basically they becomes like Client References for this consumer but for another consumer they wouldn't be. --- .../react-client/src/ReactFlightClient.js | 165 ++++++++++++++++-- .../react-markup/src/ReactMarkupServer.js | 1 + .../src/ReactNoopFlightClient.js | 1 + .../src/client/ReactFlightDOMClientBrowser.js | 1 + .../src/client/ReactFlightDOMClientNode.js | 1 + .../src/client/ReactFlightDOMClientBrowser.js | 1 + .../src/client/ReactFlightDOMClientEdge.js | 3 + .../src/client/ReactFlightDOMClientNode.js | 3 + .../src/__tests__/ReactFlightDOMEdge-test.js | 68 ++++++++ .../src/client/ReactFlightDOMClientBrowser.js | 1 + .../src/client/ReactFlightDOMClientEdge.js | 3 + .../src/client/ReactFlightDOMClientNode.js | 3 + 12 files changed, 239 insertions(+), 12 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index bc8704d8d1a56..ab527e53d8519 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -21,6 +21,7 @@ import type { ClientReference, ClientReferenceMetadata, ServerConsumerModuleMap, + ServerManifest, StringDecoder, ModuleLoading, } from './ReactFlightClientConfig'; @@ -51,6 +52,7 @@ import { import { resolveClientReference, + resolveServerReference, preloadModule, requireModule, dispatchHint, @@ -270,6 +272,7 @@ export type FindSourceMapURLCallback = ( export type Response = { _bundlerConfig: ServerConsumerModuleMap, + _serverReferenceConfig: null | ServerManifest, _moduleLoading: ModuleLoading, _callServer: CallServerCallback, _encodeFormAction: void | EncodeFormActionCallback, @@ -896,7 +899,7 @@ function waitForReference( parentObject: Object, key: string, response: Response, - map: (response: Response, model: any) => T, + map: (response: Response, model: any, parentObject: Object, key: string) => T, path: Array, ): T { let handler: InitializationHandler; @@ -938,7 +941,7 @@ function waitForReference( } value = value[path[i]]; } - const mappedValue = map(response, value); + const mappedValue = map(response, value, parentObject, key); parentObject[key] = mappedValue; // If this is the root object for a model reference, where `handler.value` @@ -1041,7 +1044,7 @@ function waitForReference( return (null: any); } -function createServerReferenceProxy, T>( +function loadServerReference, T>( response: Response, metaData: { id: any, @@ -1050,13 +1053,147 @@ function createServerReferenceProxy, T>( env?: string, // DEV-only location?: ReactCallSite, // DEV-only }, + parentObject: Object, + key: string, ): (...A) => Promise { - return createBoundServerReference( - metaData, - response._callServer, - response._encodeFormAction, - __DEV__ ? response._debugFindSourceMapURL : undefined, - ); + if (!response._serverReferenceConfig) { + // In the normal case, we can't load this Server Reference in the current environment and + // we just return a proxy to it. + return createBoundServerReference( + metaData, + response._callServer, + response._encodeFormAction, + __DEV__ ? response._debugFindSourceMapURL : undefined, + ); + } + // If we have a module mapping we can load the real version of this Server Reference. + const serverReference: ClientReference = + resolveServerReference<$FlowFixMe>( + response._serverReferenceConfig, + metaData.id, + ); + + const promise = preloadModule(serverReference); + if (!promise) { + return (requireModule(serverReference): any); + } + + let handler: InitializationHandler; + if (initializingHandler) { + handler = initializingHandler; + handler.deps++; + } else { + handler = initializingHandler = { + parent: null, + chunk: null, + value: null, + deps: 1, + errored: false, + }; + } + + function fulfill(): void { + const resolvedValue = (requireModule(serverReference): any); + parentObject[key] = resolvedValue; + + // If this is the root object for a model reference, where `handler.value` + // is a stale `null`, the resolved value can be used directly. + if (key === '' && handler.value === null) { + handler.value = resolvedValue; + } + + // If the parent object is an unparsed React element tuple, we also need to + // update the props and owner of the parsed element object (i.e. + // handler.value). + if ( + parentObject[0] === REACT_ELEMENT_TYPE && + typeof handler.value === 'object' && + handler.value !== null && + handler.value.$$typeof === REACT_ELEMENT_TYPE + ) { + const element: any = handler.value; + switch (key) { + case '3': + element.props = resolvedValue; + break; + case '4': + if (__DEV__) { + element._owner = resolvedValue; + } + break; + } + } + + handler.deps--; + + if (handler.deps === 0) { + const chunk = handler.chunk; + if (chunk === null || chunk.status !== BLOCKED) { + return; + } + const resolveListeners = chunk.value; + const initializedChunk: InitializedChunk = (chunk: any); + initializedChunk.status = INITIALIZED; + initializedChunk.value = handler.value; + if (resolveListeners !== null) { + wakeChunk(resolveListeners, handler.value); + } + } + } + + function reject(error: mixed): void { + if (handler.errored) { + // We've already errored. We could instead build up an AggregateError + // but if there are multiple errors we just take the first one like + // Promise.all. + return; + } + const blockedValue = handler.value; + handler.errored = true; + handler.value = error; + const chunk = handler.chunk; + if (chunk === null || chunk.status !== BLOCKED) { + return; + } + + if (__DEV__) { + if ( + typeof blockedValue === 'object' && + blockedValue !== null && + blockedValue.$$typeof === REACT_ELEMENT_TYPE + ) { + const element = blockedValue; + // Conceptually the error happened inside this Element but right before + // it was rendered. We don't have a client side component to render but + // we can add some DebugInfo to explain that this was conceptually a + // Server side error that errored inside this element. That way any stack + // traces will point to the nearest JSX that errored - e.g. during + // serialization. + const erroredComponent: ReactComponentInfo = { + name: getComponentNameFromType(element.type) || '', + owner: element._owner, + }; + if (enableOwnerStacks) { + // $FlowFixMe[cannot-write] + erroredComponent.debugStack = element._debugStack; + if (supportsCreateTask) { + // $FlowFixMe[cannot-write] + erroredComponent.debugTask = element._debugTask; + } + } + const chunkDebugInfo: ReactDebugInfo = + chunk._debugInfo || (chunk._debugInfo = []); + chunkDebugInfo.push(erroredComponent); + } + } + + triggerErrorOnChunk(chunk, error); + } + + promise.then(fulfill, reject); + + // Return a place holder value for now. + return (null: any); } function getOutlinedModel( @@ -1064,7 +1201,7 @@ function getOutlinedModel( reference: string, parentObject: Object, key: string, - map: (response: Response, model: any) => T, + map: (response: Response, model: any, parentObject: Object, key: string) => T, ): T { const path = reference.split(':'); const id = parseInt(path[0], 16); @@ -1099,7 +1236,7 @@ function getOutlinedModel( } value = value[path[i]]; } - const chunkValue = map(response, value); + const chunkValue = map(response, value, parentObject, key); if (__DEV__ && chunk._debugInfo) { // If we have a direct reference to an object that was rendered by a synchronous // server component, it might have some debug info about how it was rendered. @@ -1244,7 +1381,7 @@ function parseModelString( ref, parentObject, key, - createServerReferenceProxy, + loadServerReference, ); } case 'T': { @@ -1421,6 +1558,7 @@ function missingCall() { function ResponseInstance( this: $FlowFixMe, bundlerConfig: ServerConsumerModuleMap, + serverReferenceConfig: null | ServerManifest, moduleLoading: ModuleLoading, callServer: void | CallServerCallback, encodeFormAction: void | EncodeFormActionCallback, @@ -1432,6 +1570,7 @@ function ResponseInstance( ) { const chunks: Map> = new Map(); this._bundlerConfig = bundlerConfig; + this._serverReferenceConfig = serverReferenceConfig; this._moduleLoading = moduleLoading; this._callServer = callServer !== undefined ? callServer : missingCall; this._encodeFormAction = encodeFormAction; @@ -1486,6 +1625,7 @@ function ResponseInstance( export function createResponse( bundlerConfig: ServerConsumerModuleMap, + serverReferenceConfig: null | ServerManifest, moduleLoading: ModuleLoading, callServer: void | CallServerCallback, encodeFormAction: void | EncodeFormActionCallback, @@ -1498,6 +1638,7 @@ export function createResponse( // $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors return new ResponseInstance( bundlerConfig, + serverReferenceConfig, moduleLoading, callServer, encodeFormAction, diff --git a/packages/react-markup/src/ReactMarkupServer.js b/packages/react-markup/src/ReactMarkupServer.js index 8608034293a4c..d0cd8b96f823b 100644 --- a/packages/react-markup/src/ReactMarkupServer.js +++ b/packages/react-markup/src/ReactMarkupServer.js @@ -173,6 +173,7 @@ export function experimental_renderToHTML( undefined, ); const flightResponse = createFlightResponse( + null, null, null, noServerCallOrFormAction, diff --git a/packages/react-noop-renderer/src/ReactNoopFlightClient.js b/packages/react-noop-renderer/src/ReactNoopFlightClient.js index 456f8fd1bb461..346433404e235 100644 --- a/packages/react-noop-renderer/src/ReactNoopFlightClient.js +++ b/packages/react-noop-renderer/src/ReactNoopFlightClient.js @@ -62,6 +62,7 @@ function read(source: Source, options: ReadOptions): Thenable { const response = createResponse( source, null, + null, undefined, undefined, undefined, diff --git a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js index abaa793c96a71..afabc291041bf 100644 --- a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientBrowser.js @@ -51,6 +51,7 @@ function createResponseFromOptions(options: void | Options) { return createResponse( options && options.moduleBaseURL ? options.moduleBaseURL : '', null, + null, options && options.callServer ? options.callServer : undefined, undefined, // encodeFormAction undefined, // nonce diff --git a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js index dd7ebbcd9d876..2e1c5566423ca 100644 --- a/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js +++ b/packages/react-server-dom-esm/src/client/ReactFlightDOMClientNode.js @@ -62,6 +62,7 @@ function createFromNodeStream( ): Thenable { const response: Response = createResponse( moduleRootPath, + null, moduleBaseURL, noServerCall, options ? options.encodeFormAction : undefined, diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js index 0d566a57caf5f..b6b55e4586e16 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientBrowser.js @@ -48,6 +48,7 @@ export type Options = { function createResponseFromOptions(options: void | Options) { return createResponse( + null, null, null, options && options.callServer ? options.callServer : undefined, diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js index f9ac4e9d257de..973d46448329c 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js @@ -19,11 +19,13 @@ import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient'; import type { ServerConsumerModuleMap, ModuleLoading, + ServerManifest, } from 'react-client/src/ReactFlightClientConfig'; type ServerConsumerManifest = { moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, + serverModuleMap: null | ServerManifest, }; import { @@ -78,6 +80,7 @@ export type Options = { function createResponseFromOptions(options: Options) { return createResponse( options.serverManifest.moduleMap, + options.serverManifest.serverModuleMap, options.serverManifest.moduleLoading, noServerCall, options.encodeFormAction, diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js index 528df26f11f96..2ee76fa3b41c9 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientNode.js @@ -17,11 +17,13 @@ import type { import type { ServerConsumerModuleMap, ModuleLoading, + ServerManifest, } from 'react-client/src/ReactFlightClientConfig'; type ServerConsumerManifest = { moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, + serverModuleMap: null | ServerManifest, }; import type {Readable} from 'stream'; @@ -71,6 +73,7 @@ function createFromNodeStream( ): Thenable { const response: Response = createResponse( serverConsumerManifest.moduleMap, + serverConsumerManifest.serverModuleMap, serverConsumerManifest.moduleLoading, noServerCall, options ? options.encodeFormAction : undefined, diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index 41cffe84d249b..eedf10847d581 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -26,6 +26,7 @@ global.AsyncLocalStorage = require('async_hooks').AsyncLocalStorage; let serverExports; let clientExports; let webpackMap; +let webpackServerMap; let webpackModules; let webpackModuleLoading; let React; @@ -63,6 +64,7 @@ describe('ReactFlightDOMEdge', () => { serverExports = WebpackMock.serverExports; clientExports = WebpackMock.clientExports; webpackMap = WebpackMock.webpackMap; + webpackServerMap = WebpackMock.webpackServerMap; webpackModules = WebpackMock.webpackModules; webpackModuleLoading = WebpackMock.moduleLoading; @@ -212,6 +214,72 @@ describe('ReactFlightDOMEdge', () => { expect(result).toEqual('Client Component'); }); + it('should be able to load a server reference on a consuming server if a mapping exists', async () => { + function greet() { + return 'hi'; + } + const ServerModule = serverExports({ + greet, + }); + + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream( + { + method: ServerModule.greet, + }, + webpackMap, + ), + ); + const response = ReactServerDOMClient.createFromReadableStream(stream, { + serverConsumerManifest: { + moduleMap: webpackMap, + serverModuleMap: webpackServerMap, + moduleLoading: webpackModuleLoading, + }, + }); + + const result = await response; + + expect(result.method).toBe(greet); + }); + + it('should be able to load a server reference on a consuming server if a mapping exists (async)', async () => { + let resolve; + const chunkPromise = new Promise(r => (resolve = r)); + + function greet() { + return 'hi'; + } + const ServerModule = serverExports( + { + greet, + }, + chunkPromise, + ); + + const stream = await serverAct(() => + ReactServerDOMServer.renderToReadableStream( + { + method: ServerModule.greet, + }, + webpackMap, + ), + ); + const response = ReactServerDOMClient.createFromReadableStream(stream, { + serverConsumerManifest: { + moduleMap: webpackMap, + serverModuleMap: webpackServerMap, + moduleLoading: webpackModuleLoading, + }, + }); + + await resolve(); + + const result = await response; + + expect(result.method).toBe(greet); + }); + it('should encode long string in a compact format', async () => { const testString = '"\n\t'.repeat(500) + '🙃'; const testString2 = 'hello'.repeat(400); diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js index 0d566a57caf5f..b6b55e4586e16 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js @@ -48,6 +48,7 @@ export type Options = { function createResponseFromOptions(options: void | Options) { return createResponse( + null, null, null, options && options.callServer ? options.callServer : undefined, diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js index 23bd02af42a21..509950bc65135 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientEdge.js @@ -19,11 +19,13 @@ import type {ReactServerValue} from 'react-client/src/ReactFlightReplyClient'; import type { ServerConsumerModuleMap, ModuleLoading, + ServerManifest, } from 'react-client/src/ReactFlightClientConfig'; type ServerConsumerManifest = { moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, + serverModuleMap: null | ServerManifest, }; import { @@ -78,6 +80,7 @@ export type Options = { function createResponseFromOptions(options: Options) { return createResponse( options.serverConsumerManifest.moduleMap, + options.serverConsumerManifest.serverModuleMap, options.serverConsumerManifest.moduleLoading, noServerCall, options.encodeFormAction, diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js index eab37b3bce924..22c8928432b74 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightDOMClientNode.js @@ -17,11 +17,13 @@ import type { import type { ServerConsumerModuleMap, ModuleLoading, + ServerManifest, } from 'react-client/src/ReactFlightClientConfig'; type ServerConsumerManifest = { moduleMap: ServerConsumerModuleMap, moduleLoading: ModuleLoading, + serverModuleMap: null | ServerManifest, }; import type {Readable} from 'stream'; @@ -72,6 +74,7 @@ function createFromNodeStream( ): Thenable { const response: Response = createResponse( serverConsumerManifest.moduleMap, + serverConsumerManifest.serverModuleMap, serverConsumerManifest.moduleLoading, noServerCall, options ? options.encodeFormAction : undefined, From d49123f73f12564223c890bfa36be537de2c571d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sat, 19 Oct 2024 22:33:28 -0400 Subject: [PATCH 305/426] Expose prerender() for SSG in stable (#31298) When we added `renderToReadableStream` we added the `allReady` helper to make it easier to do SSG rendering but it's kind of awkward to wire up that way. Since we're also discouraging `renderToString` in React 19 the cliff is kind of awkward. ([As noted by Docusaurus.](https://github.com/facebook/react/pull/24752#issuecomment-2178309299)) The idea of the `react-dom/static` `prerender` API was that this would be the replacement for SSG rendering. Awkwardly this entry point actually already exists in stable but it has only `undefined` exports. Since then we've also added other useful heuristics into the `prerender` branch that makes this really the favored and easiest to use API for the prerender (SSG/ISR) use case. `prerender` is also used for Partial Prerendering but that part is still experimental. However, we can expose only the `prerender` API on `react-dom/static` without it returning the `postponeState`. Instead the stream is on `prelude`. The naming is a bit awkward if you don't consider resuming but it's the same thing. It's really just `renderToReadable` stream with automatic `allReady` and better heuristics for prerendering. --- .../src/__tests__/ReactDOMFizzStatic-test.js | 16 ++++++------- .../ReactDOMFizzStaticBrowser-test.js | 24 +++++-------------- .../src/server/ReactDOMFizzStaticBrowser.js | 15 ++++++++---- .../src/server/ReactDOMFizzStaticEdge.js | 15 ++++++++---- .../src/server/ReactDOMFizzStaticNode.js | 15 ++++++++---- .../server/react-dom-server.browser.stable.js | 1 + .../server/react-dom-server.edge.stable.js | 1 + .../server/react-dom-server.node.stable.js | 1 + 8 files changed, 49 insertions(+), 39 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js index 03db4e3f5ed8f..96e6538cd2196 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzStatic-test.js @@ -32,9 +32,7 @@ describe('ReactDOMFizzStatic', () => { React = require('react'); ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); - if (__EXPERIMENTAL__) { - ReactDOMFizzStatic = require('react-dom/static'); - } + ReactDOMFizzStatic = require('react-dom/static'); Stream = require('stream'); Suspense = React.Suspense; @@ -212,7 +210,6 @@ describe('ReactDOMFizzStatic', () => { return readText(text); } - // @gate experimental it('should render a fully static document, send it and then hydrate it', async () => { function App() { return ( @@ -230,7 +227,11 @@ describe('ReactDOMFizzStatic', () => { const result = await promise; - expect(result.postponed).toBe(null); + expect(result.postponed).toBe( + gate(flags => flags.enableHalt || flags.enablePostpone) + ? null + : undefined, + ); await act(async () => { result.prelude.pipe(writable); @@ -244,7 +245,6 @@ describe('ReactDOMFizzStatic', () => { expect(getVisibleChildren(container)).toEqual(
Hello
); }); - // @gate experimental it('should support importMap option', async () => { const importMap = { foo: 'path/to/foo.js', @@ -265,7 +265,6 @@ describe('ReactDOMFizzStatic', () => { ]); }); - // @gate experimental it('supports onHeaders', async () => { let headers; function onHeaders(x) { @@ -300,7 +299,7 @@ describe('ReactDOMFizzStatic', () => { expect(getVisibleChildren(container)).toEqual('hello'); }); - // @gate experimental && enablePostpone + // @gate enablePostpone it('includes stylesheet preloads in onHeaders when postponing in the Shell', async () => { let headers; function onHeaders(x) { @@ -336,7 +335,6 @@ describe('ReactDOMFizzStatic', () => { expect(getVisibleChildren(container)).toEqual(undefined); }); - // @gate experimental it('will prerender Suspense fallbacks before children', async () => { const values = []; function Indirection({children}) { diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js index 1512e1d4c7e99..535bd5d7ba815 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzStaticBrowser-test.js @@ -42,9 +42,7 @@ describe('ReactDOMFizzStaticBrowser', () => { React = require('react'); ReactDOM = require('react-dom'); ReactDOMFizzServer = require('react-dom/server.browser'); - if (__EXPERIMENTAL__) { - ReactDOMFizzStatic = require('react-dom/static.browser'); - } + ReactDOMFizzStatic = require('react-dom/static.browser'); Suspense = React.Suspense; container = document.createElement('div'); document.body.appendChild(container); @@ -131,7 +129,6 @@ describe('ReactDOMFizzStaticBrowser', () => { await insertNodesAndExecuteScripts(temp, container, null); } - // @gate experimental it('should call prerender', async () => { const result = await serverAct(() => ReactDOMFizzStatic.prerender(
hello world
), @@ -140,7 +137,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(prelude).toMatchInlineSnapshot(`"
hello world
"`); }); - // @gate experimental it('should emit DOCTYPE at the root of the document', async () => { const result = await serverAct(() => ReactDOMFizzStatic.prerender( @@ -155,7 +151,6 @@ describe('ReactDOMFizzStaticBrowser', () => { ); }); - // @gate experimental it('should emit bootstrap script src at the end', async () => { const result = await serverAct(() => ReactDOMFizzStatic.prerender(
hello world
, { @@ -170,7 +165,6 @@ describe('ReactDOMFizzStaticBrowser', () => { ); }); - // @gate experimental it('emits all HTML as one unit', async () => { let hasLoaded = false; let resolve; @@ -202,7 +196,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(prelude).toMatchInlineSnapshot(`"
Done
"`); }); - // @gate experimental it('should reject the promise when an error is thrown at the root', async () => { const reportedErrors = []; let caughtError = null; @@ -226,7 +219,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(reportedErrors).toEqual([theError]); }); - // @gate experimental it('should reject the promise when an error is thrown inside a fallback', async () => { const reportedErrors = []; let caughtError = null; @@ -252,7 +244,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(reportedErrors).toEqual([theError]); }); - // @gate experimental it('should not error the stream when an error is thrown inside suspense boundary', async () => { const reportedErrors = []; const result = await serverAct(() => @@ -275,7 +266,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(reportedErrors).toEqual([theError]); }); - // @gate experimental it('should be able to complete by aborting even if the promise never resolves', async () => { const errors = []; const controller = new AbortController(); @@ -306,7 +296,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(errors).toEqual(['The operation was aborted.']); }); - // @gate experimental // @gate !enableHalt it('should reject if aborting before the shell is complete and enableHalt is disabled', async () => { const errors = []; @@ -376,7 +365,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(content).toBe(''); }); - // @gate experimental it('should be able to abort before something suspends', async () => { const errors = []; const controller = new AbortController(); @@ -419,7 +407,6 @@ describe('ReactDOMFizzStaticBrowser', () => { } }); - // @gate experimental // @gate !enableHalt it('should reject if passing an already aborted signal and enableHalt is disabled', async () => { const errors = []; @@ -493,7 +480,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(content).toBe(''); }); - // @gate experimental it('supports custom abort reasons with a string', async () => { const promise = new Promise(r => {}); function Wait() { @@ -536,7 +522,6 @@ describe('ReactDOMFizzStaticBrowser', () => { expect(errors).toEqual(['foobar', 'foobar']); }); - // @gate experimental it('supports custom abort reasons with an Error', async () => { const promise = new Promise(r => {}); function Wait() { @@ -1610,7 +1595,6 @@ describe('ReactDOMFizzStaticBrowser', () => { ); }); - // @gate experimental it('logs an error if onHeaders throws but continues the prerender', async () => { const errors = []; function onError(error) { @@ -1627,7 +1611,11 @@ describe('ReactDOMFizzStaticBrowser', () => { onError, }), ); - expect(prerendered.postponed).toBe(null); + expect(prerendered.postponed).toBe( + gate(flags => flags.enableHalt || flags.enablePostpone) + ? null + : undefined, + ); expect(errors).toEqual(['bad onHeaders']); await readIntoContainer(prerendered.prelude); diff --git a/packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js b/packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js index 6785515bbebe7..82d7b12f54b6b 100644 --- a/packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js +++ b/packages/react-dom/src/server/ReactDOMFizzStaticBrowser.js @@ -38,6 +38,8 @@ import { createRootFormatContext, } from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; +import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags'; + import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion'; ensureCorrectIsomorphicReactVersion(); @@ -85,10 +87,15 @@ function prerender( {highWaterMark: 0}, ); - const result = { - postponed: getPostponedState(request), - prelude: stream, - }; + const result: StaticResult = + enablePostpone || enableHalt + ? { + postponed: getPostponedState(request), + prelude: stream, + } + : ({ + prelude: stream, + }: any); resolve(result); } diff --git a/packages/react-dom/src/server/ReactDOMFizzStaticEdge.js b/packages/react-dom/src/server/ReactDOMFizzStaticEdge.js index 5a7467002cb5c..1243b18adaab1 100644 --- a/packages/react-dom/src/server/ReactDOMFizzStaticEdge.js +++ b/packages/react-dom/src/server/ReactDOMFizzStaticEdge.js @@ -38,6 +38,8 @@ import { createRootFormatContext, } from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; +import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags'; + import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion'; ensureCorrectIsomorphicReactVersion(); @@ -85,10 +87,15 @@ function prerender( {highWaterMark: 0}, ); - const result = { - postponed: getPostponedState(request), - prelude: stream, - }; + const result: StaticResult = + enablePostpone || enableHalt + ? { + postponed: getPostponedState(request), + prelude: stream, + } + : ({ + prelude: stream, + }: any); resolve(result); } diff --git a/packages/react-dom/src/server/ReactDOMFizzStaticNode.js b/packages/react-dom/src/server/ReactDOMFizzStaticNode.js index 9b9cd680c16b9..e90e17cc207ee 100644 --- a/packages/react-dom/src/server/ReactDOMFizzStaticNode.js +++ b/packages/react-dom/src/server/ReactDOMFizzStaticNode.js @@ -39,6 +39,8 @@ import { createRootFormatContext, } from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; +import {enablePostpone, enableHalt} from 'shared/ReactFeatureFlags'; + import {ensureCorrectIsomorphicReactVersion} from '../shared/ensureCorrectIsomorphicReactVersion'; ensureCorrectIsomorphicReactVersion(); @@ -94,10 +96,15 @@ function prerenderToNodeStream( }); const writable = createFakeWritable(readable); - const result = { - postponed: getPostponedState(request), - prelude: readable, - }; + const result: StaticResult = + enablePostpone || enableHalt + ? { + postponed: getPostponedState(request), + prelude: readable, + } + : ({ + prelude: readable, + }: any); resolve(result); } const resumableState = createResumableState( diff --git a/packages/react-dom/src/server/react-dom-server.browser.stable.js b/packages/react-dom/src/server/react-dom-server.browser.stable.js index 3471bba15ac94..2c8f8b5dd59a3 100644 --- a/packages/react-dom/src/server/react-dom-server.browser.stable.js +++ b/packages/react-dom/src/server/react-dom-server.browser.stable.js @@ -8,3 +8,4 @@ */ export {renderToReadableStream, version} from './ReactDOMFizzServerBrowser.js'; +export {prerender} from './ReactDOMFizzStaticBrowser.js'; diff --git a/packages/react-dom/src/server/react-dom-server.edge.stable.js b/packages/react-dom/src/server/react-dom-server.edge.stable.js index b2f0278099ce3..5f47ecafd371a 100644 --- a/packages/react-dom/src/server/react-dom-server.edge.stable.js +++ b/packages/react-dom/src/server/react-dom-server.edge.stable.js @@ -8,3 +8,4 @@ */ export {renderToReadableStream, version} from './ReactDOMFizzServerEdge.js'; +export {prerender} from './ReactDOMFizzStaticEdge.js'; diff --git a/packages/react-dom/src/server/react-dom-server.node.stable.js b/packages/react-dom/src/server/react-dom-server.node.stable.js index bd17b91a9602a..4003622625110 100644 --- a/packages/react-dom/src/server/react-dom-server.node.stable.js +++ b/packages/react-dom/src/server/react-dom-server.node.stable.js @@ -8,3 +8,4 @@ */ export {renderToPipeableStream, version} from './ReactDOMFizzServerNode.js'; +export {prerenderToNodeStream} from './ReactDOMFizzStaticNode.js'; From c1e1358b2dc9848c20be43bfde248ffb90966da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 20 Oct 2024 00:02:48 -0400 Subject: [PATCH 306/426] [Flight] Align turbopack option name with webpack name (#31301) This was renamed in #31300. --- .../src/__tests__/ReactFlightTurbopackDOMEdge-test.js | 2 +- .../src/client/ReactFlightDOMClientEdge.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js index 5e4fd2cdd5bd9..377c27a25ab5a 100644 --- a/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js +++ b/packages/react-server-dom-turbopack/src/__tests__/ReactFlightTurbopackDOMEdge-test.js @@ -97,7 +97,7 @@ describe('ReactFlightTurbopackDOMEdge', () => { turbopackMap, ); const response = ReactServerDOMClient.createFromReadableStream(stream, { - serverManifest: { + serverConsumerManifest: { moduleMap: translationMap, moduleLoading: null, }, diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js index 973d46448329c..509950bc65135 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightDOMClientEdge.js @@ -68,7 +68,7 @@ type EncodeFormActionCallback =
( ) => ReactCustomFormAction; export type Options = { - serverManifest: ServerConsumerManifest, + serverConsumerManifest: ServerConsumerManifest, nonce?: string, encodeFormAction?: EncodeFormActionCallback, temporaryReferences?: TemporaryReferenceSet, @@ -79,9 +79,9 @@ export type Options = { function createResponseFromOptions(options: Options) { return createResponse( - options.serverManifest.moduleMap, - options.serverManifest.serverModuleMap, - options.serverManifest.moduleLoading, + options.serverConsumerManifest.moduleMap, + options.serverConsumerManifest.serverModuleMap, + options.serverConsumerManifest.moduleLoading, noServerCall, options.encodeFormAction, typeof options.nonce === 'string' ? options.nonce : undefined, From 251b666dedde430b7767e1745e71155db8ec585d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 20 Oct 2024 02:12:06 -0400 Subject: [PATCH 307/426] [Flight] Handle bound arguments for loaded server references (#31302) Follow up to #31300. I forgot to pass the bound arguments to the loaded function. --- packages/react-client/src/ReactFlightClient.js | 15 ++++++++++++--- .../src/__tests__/ReactFlightDOMEdge-test.js | 12 ++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index ab527e53d8519..ad6bf34d97152 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -1073,10 +1073,11 @@ function loadServerReference, T>( metaData.id, ); - const promise = preloadModule(serverReference); - if (!promise) { + let promise = preloadModule(serverReference); + if (!promise && !metaData.bound) { return (requireModule(serverReference): any); } + promise = Promise.all([promise, metaData.bound]); let handler: InitializationHandler; if (initializingHandler) { @@ -1093,7 +1094,15 @@ function loadServerReference, T>( } function fulfill(): void { - const resolvedValue = (requireModule(serverReference): any); + let resolvedValue = (requireModule(serverReference): any); + + if (metaData.bound) { + // This promise is coming from us and should have initilialized by now. + const boundArgs: Array = (metaData.bound: any).value.slice(0); + boundArgs.unshift(null); // this + resolvedValue = resolvedValue.bind.apply(resolvedValue, boundArgs); + } + parentObject[key] = resolvedValue; // If this is the root object for a model reference, where `handler.value` diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index eedf10847d581..ed349cde81f09 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -215,8 +215,8 @@ describe('ReactFlightDOMEdge', () => { }); it('should be able to load a server reference on a consuming server if a mapping exists', async () => { - function greet() { - return 'hi'; + function greet(name) { + return 'hi, ' + name; } const ServerModule = serverExports({ greet, @@ -226,6 +226,7 @@ describe('ReactFlightDOMEdge', () => { ReactServerDOMServer.renderToReadableStream( { method: ServerModule.greet, + boundMethod: ServerModule.greet.bind(null, 'there'), }, webpackMap, ), @@ -241,14 +242,15 @@ describe('ReactFlightDOMEdge', () => { const result = await response; expect(result.method).toBe(greet); + expect(result.boundMethod()).toBe('hi, there'); }); it('should be able to load a server reference on a consuming server if a mapping exists (async)', async () => { let resolve; const chunkPromise = new Promise(r => (resolve = r)); - function greet() { - return 'hi'; + function greet(name) { + return 'hi, ' + name; } const ServerModule = serverExports( { @@ -261,6 +263,7 @@ describe('ReactFlightDOMEdge', () => { ReactServerDOMServer.renderToReadableStream( { method: ServerModule.greet, + boundMethod: ServerModule.greet.bind(null, 'there'), }, webpackMap, ), @@ -278,6 +281,7 @@ describe('ReactFlightDOMEdge', () => { const result = await response; expect(result.method).toBe(greet); + expect(result.boundMethod()).toBe('hi, there'); }); it('should encode long string in a compact format', async () => { From f11bd3439cfd0e95c490a58059562b781c34c3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 20 Oct 2024 02:23:31 -0400 Subject: [PATCH 308/426] Fix types (#31303) --- packages/react-client/src/ReactFlightClient.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index ad6bf34d97152..35d21f945bb3b 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -1073,11 +1073,16 @@ function loadServerReference, T>( metaData.id, ); - let promise = preloadModule(serverReference); - if (!promise && !metaData.bound) { - return (requireModule(serverReference): any); + let promise: null | Thenable = preloadModule(serverReference); + if (!promise) { + if (!metaData.bound) { + return (requireModule(serverReference): any); + } else { + promise = metaData.bound; + } + } else if (metaData.bound) { + promise = Promise.all([promise, metaData.bound]); } - promise = Promise.all([promise, metaData.bound]); let handler: InitializationHandler; if (initializingHandler) { From 65a56d0e99261481c721334a3ec4561d173594cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Sun, 20 Oct 2024 02:35:15 -0400 Subject: [PATCH 309/426] Fix timing issue with fake promise resolving sync (#31304) --- packages/react-client/src/ReactFlightClient.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 35d21f945bb3b..ca0af0206560e 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -1078,7 +1078,7 @@ function loadServerReference, T>( if (!metaData.bound) { return (requireModule(serverReference): any); } else { - promise = metaData.bound; + promise = Promise.resolve(metaData.bound); } } else if (metaData.bound) { promise = Promise.all([promise, metaData.bound]); From 69d4b800a6c31561bd928eef4a4592fdb38471cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 21 Oct 2024 14:52:10 -0400 Subject: [PATCH 310/426] [Flight] Support Async Modules in Server References (#31313) This is required to support for example top level await in a "use server" module or dependency of a "use server". --- .../ReactFlightClientConfigBundlerWebpack.js | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js index 521b19e5a7ad4..e3530021256e3 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js @@ -86,6 +86,13 @@ export function resolveClientReference( } name = metadata[NAME]; } + // Note that resolvedModuleData.async may be set if this is an Async Module. + // For Client References we don't actually care because what matters is whether + // the consumer expects an unwrapped async module or just a raw Promise so it + // has to already know which one it wants. + // We could error if this is an Async Import but it's not an Async Module. + // However, we also support plain CJS exporting a top level Promise which is not + // an Async Module according to the bundle graph but is effectively the same. if (isAsyncImport(metadata)) { return [ resolvedModuleData.id, @@ -128,7 +135,19 @@ export function resolveServerReference( ); } } - // TODO: This needs to return async: true if it's an async module. + if (resolvedModuleData.async) { + // If the module is marked as async in a Client Reference, we don't actually care. + // What matters is whether the consumer wants to unwrap it or not. + // For Server References, it is different because the consumer is completely internal + // to the bundler. So instead of passing it to each reference we can mark it in the + // manifest. + return [ + resolvedModuleData.id, + resolvedModuleData.chunks, + name, + 1 /* async */, + ]; + } return [resolvedModuleData.id, resolvedModuleData.chunks, name]; } From 45804af18d589fd2c181f3b020f07661c46b73ea Mon Sep 17 00:00:00 2001 From: Sam Zhou Date: Mon, 21 Oct 2024 16:17:41 -0700 Subject: [PATCH 311/426] [flow] Eliminate usage of more than 1-arg `React.AbstractComponent` in React codebase (#31314) ## Summary In order to adopt react 19's ref-as-prop model, Flow needs to eliminate all the places where they are treated differently. `React.AbstractComponent` is the worst example of this, and we need to eliminate it. This PR eliminates them from the react repo, and only keeps the one that has 1 argument of props. ## How did you test this change? yarn flow --- .eslintrc.js | 1 + packages/react-devtools-inline/src/frontend.js | 2 +- .../src/devtools/ContextMenu/types.js | 8 +++++--- .../src/devtools/views/Components/Components.js | 2 +- .../src/devtools/views/portaledContent.js | 4 ++-- .../src/app/InspectableElements/CustomHooks.js | 6 ++++-- packages/react-markup/src/ReactMarkupServer.js | 2 +- .../src/ReactNativeFiberHostComponent.js | 5 ++--- .../src/ReactNativePublicCompat.js | 4 ++-- .../src/ReactNativeTypes.js | 17 ++++++++--------- .../react-reconciler/src/ReactTestSelectors.js | 4 ++-- packages/react-server/src/ReactFlightServer.js | 2 +- packages/react/index.development.js | 6 +----- packages/react/index.js | 6 +----- packages/react/src/ReactForwardRef.js | 5 ++++- 15 files changed, 36 insertions(+), 38 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3366a38517c93..faeb5077f21a8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -569,6 +569,7 @@ module.exports = { React$Node: 'readonly', React$Portal: 'readonly', React$Ref: 'readonly', + React$RefSetter: 'readonly', ReadableStreamController: 'readonly', ReadableStreamReader: 'readonly', RequestInfo: 'readonly', diff --git a/packages/react-devtools-inline/src/frontend.js b/packages/react-devtools-inline/src/frontend.js index f96d29ac50745..056d5d2c27052 100644 --- a/packages/react-devtools-inline/src/frontend.js +++ b/packages/react-devtools-inline/src/frontend.js @@ -52,7 +52,7 @@ export function initialize( bridge?: FrontendBridge, store?: Store, } = {}, -): React.AbstractComponent { +): React.ComponentType { if (bridge == null) { bridge = createBridge(contentWindow); } diff --git a/packages/react-devtools-shared/src/devtools/ContextMenu/types.js b/packages/react-devtools-shared/src/devtools/ContextMenu/types.js index 2436fcc2d1b80..e2e8cecae33ac 100644 --- a/packages/react-devtools-shared/src/devtools/ContextMenu/types.js +++ b/packages/react-devtools-shared/src/devtools/ContextMenu/types.js @@ -7,7 +7,7 @@ * @flow */ -import type {Node as ReactNode, AbstractComponent, ElementRef} from 'react'; +import type {Node as ReactNode} from 'react'; export type ContextMenuItem = { onClick: () => void, @@ -25,5 +25,7 @@ export type ContextMenuHandle = { hide(): void, }; -export type ContextMenuComponent = AbstractComponent<{}, ContextMenuHandle>; -export type ContextMenuRef = {current: ElementRef | null}; +/*:: +export type ContextMenuComponent = component(ref: React$RefSetter); +*/ +export type ContextMenuRef = {current: ContextMenuHandle | null}; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Components.js b/packages/react-devtools-shared/src/devtools/views/Components/Components.js index f0b309d3f1a2a..995f1d92cf323 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Components.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Components.js @@ -246,4 +246,4 @@ function setResizeCSSVariable( } } -export default (portaledContent(Components): React$AbstractComponent<{}>); +export default (portaledContent(Components): React$ComponentType<{}>); diff --git a/packages/react-devtools-shared/src/devtools/views/portaledContent.js b/packages/react-devtools-shared/src/devtools/views/portaledContent.js index efd0a4e30d272..b2be6867d93b8 100644 --- a/packages/react-devtools-shared/src/devtools/views/portaledContent.js +++ b/packages/react-devtools-shared/src/devtools/views/portaledContent.js @@ -17,8 +17,8 @@ import ThemeProvider from './ThemeProvider'; export type Props = {portalContainer?: Element, ...}; export default function portaledContent( - Component: React$AbstractComponent, -): React$AbstractComponent { + Component: React$ComponentType, +): React$ComponentType { return function PortaledContent({portalContainer, ...rest}: Props) { const store = useContext(StoreContext); diff --git a/packages/react-devtools-shell/src/app/InspectableElements/CustomHooks.js b/packages/react-devtools-shell/src/app/InspectableElements/CustomHooks.js index a05acf138d3d3..487c0be4da750 100644 --- a/packages/react-devtools-shell/src/app/InspectableElements/CustomHooks.js +++ b/packages/react-devtools-shell/src/app/InspectableElements/CustomHooks.js @@ -72,7 +72,7 @@ function useDeepHookF() { const ContextA = createContext('A'); const ContextB = createContext('B'); -function FunctionWithHooks(props: any, ref: React$Ref) { +function FunctionWithHooks(props: any, ref: React$RefSetter) { const [count, updateCount] = useState(0); // eslint-disable-next-line no-unused-vars const contextValueA = useContext(ContextA); @@ -108,7 +108,9 @@ function FunctionWithHooks(props: any, ref: React$Ref) { const MemoWithHooks = memo(FunctionWithHooks); const ForwardRefWithHooks = forwardRef(FunctionWithHooks); -function wrapWithHoc(Component: (props: any, ref: React$Ref) => any) { +function wrapWithHoc( + Component: (props: any, ref: React$RefSetter) => any, +) { function Hoc() { return ; } diff --git a/packages/react-markup/src/ReactMarkupServer.js b/packages/react-markup/src/ReactMarkupServer.js index d0cd8b96f823b..d3950c568f7ce 100644 --- a/packages/react-markup/src/ReactMarkupServer.js +++ b/packages/react-markup/src/ReactMarkupServer.js @@ -46,7 +46,7 @@ import { type ReactMarkupNodeList = // This is the intersection of ReactNodeList and ReactClientValue minus // Client/ServerReferences. - | React$Element> + | React$Element> | LazyComponent | React$Element | string diff --git a/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js b/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js index 80151468dd24a..28d259fc5d0e5 100644 --- a/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js +++ b/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js @@ -7,9 +7,8 @@ * @flow */ -import type {ElementRef} from 'react'; import type { - HostComponent, + HostInstance, MeasureInWindowOnSuccessCallback, MeasureLayoutOnSuccessCallback, MeasureOnSuccessCallback, @@ -72,7 +71,7 @@ class ReactNativeFiberHostComponent implements INativeMethods { } measureLayout( - relativeToNativeNode: number | ElementRef>, + relativeToNativeNode: number | HostInstance, onSuccess: MeasureLayoutOnSuccessCallback, onFail?: () => void /* currently unused */, ) { diff --git a/packages/react-native-renderer/src/ReactNativePublicCompat.js b/packages/react-native-renderer/src/ReactNativePublicCompat.js index c50b881c150c1..c8883261f7fc4 100644 --- a/packages/react-native-renderer/src/ReactNativePublicCompat.js +++ b/packages/react-native-renderer/src/ReactNativePublicCompat.js @@ -32,7 +32,7 @@ import { export function findHostInstance_DEPRECATED( componentOrHandle: ?(ElementRef | number), -): ?ElementRef> { +): ?ElementRef> { if (__DEV__) { const owner = currentOwner; if (owner !== null && isRendering && owner.stateNode !== null) { @@ -225,7 +225,7 @@ export function getNodeFromInternalInstanceHandle( // Should have been PublicInstance from ReactFiberConfigFabric type FabricPublicInstance = mixed; // Should have been PublicInstance from ReactFiberConfigNative -type PaperPublicInstance = HostComponent; +type PaperPublicInstance = HostComponent; // Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN. export function isChildPublicInstance( diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 540ac1cf2aa70..80d9df6f84c5c 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -9,12 +9,7 @@ * @flow strict */ -import type { - ElementRef, - ElementType, - MixedElement, - AbstractComponent, -} from 'react'; +import type {ElementRef, ElementType, MixedElement} from 'react'; export type MeasureOnSuccessCallback = ( x: number, @@ -137,7 +132,9 @@ declare const ensureNativeMethodsAreSynced: NativeMethods; (ensureNativeMethodsAreSynced: INativeMethods); export type HostInstance = NativeMethods; -export type HostComponent = AbstractComponent; +/*:: +export type HostComponent = component(ref: React$RefSetter, ...Config); +*/ type InspectorDataProps = $ReadOnly<{ [propName: string]: string, @@ -208,8 +205,10 @@ export type ReactNativeType = { componentOrHandle: ?(ElementRef | number), ): ?number, isChildPublicInstance( - parent: PublicInstance | HostComponent, - child: PublicInstance | HostComponent, + // eslint-disable-next-line no-undef + parent: PublicInstance | HostComponent, + // eslint-disable-next-line no-undef + child: PublicInstance | HostComponent, ): boolean, dispatchCommand( handle: HostInstance, diff --git a/packages/react-reconciler/src/ReactTestSelectors.js b/packages/react-reconciler/src/ReactTestSelectors.js index 34f0529f8cdeb..de3e95c281e60 100644 --- a/packages/react-reconciler/src/ReactTestSelectors.js +++ b/packages/react-reconciler/src/ReactTestSelectors.js @@ -48,7 +48,7 @@ type Type = symbol | number; type ComponentSelector = { $$typeof: Type, - value: React$AbstractComponent, + value: React$ComponentType, }; type HasPseudoClassSelector = { @@ -79,7 +79,7 @@ type Selector = | TestNameSelector; export function createComponentSelector( - component: React$AbstractComponent, + component: React$ComponentType, ): ComponentSelector { return { $$typeof: COMPONENT_TYPE, diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index ca004a6e7971f..ca238271e20d6 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -297,7 +297,7 @@ type ReactJSONValue = // Serializable values export type ReactClientValue = // Server Elements and Lazy Components are unwrapped on the Server - | React$Element> + | React$Element> | LazyComponent // References are passed by their value | ClientReference diff --git a/packages/react/index.development.js b/packages/react/index.development.js index bf08db7a58418..398e67240416d 100644 --- a/packages/react/index.development.js +++ b/packages/react/index.development.js @@ -9,14 +9,10 @@ // Keep in sync with https://github.com/facebook/flow/blob/main/lib/react.js export type ComponentType<-P> = React$ComponentType

; -export type AbstractComponent< - -Config, - +Instance = mixed, -> = React$AbstractComponent; +export type AbstractComponent<-Config> = React$AbstractComponent; export type ElementType = React$ElementType; export type Element<+C> = React$Element; export type Key = React$Key; -export type Ref = React$Ref; export type Node = React$Node; export type Context = React$Context; export type Portal = React$Portal; diff --git a/packages/react/index.js b/packages/react/index.js index 0c048c4e9c297..2edb0a2c1de09 100644 --- a/packages/react/index.js +++ b/packages/react/index.js @@ -9,15 +9,11 @@ // Keep in sync with https://github.com/facebook/flow/blob/main/lib/react.js export type ComponentType<-P> = React$ComponentType

; -export type AbstractComponent< - -Config, - +Instance = mixed, -> = React$AbstractComponent; +export type AbstractComponent<-Config> = React$AbstractComponent; export type ElementType = React$ElementType; export type Element<+C> = React$Element; export type MixedElement = React$Element; export type Key = React$Key; -export type Ref = React$Ref; export type Node = React$Node; export type Context = React$Context; export type Portal = React$Portal; diff --git a/packages/react/src/ReactForwardRef.js b/packages/react/src/ReactForwardRef.js index 8978763ba15ef..4f891d609ff48 100644 --- a/packages/react/src/ReactForwardRef.js +++ b/packages/react/src/ReactForwardRef.js @@ -10,7 +10,10 @@ import {REACT_FORWARD_REF_TYPE, REACT_MEMO_TYPE} from 'shared/ReactSymbols'; export function forwardRef( - render: (props: Props, ref: React$Ref) => React$Node, + render: ( + props: Props, + ref: React$RefSetter>, + ) => React$Node, ) { if (__DEV__) { if (render != null && render.$$typeof === REACT_MEMO_TYPE) { From ae90522bc6ea80d87f22e845024dc82e2c05e3d5 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 22 Oct 2024 19:51:58 +0200 Subject: [PATCH 312/426] chore: remove unsued deps from React Compiler Babel plugin (#31315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Since the Babel plugin is bundled into a single file (except for `@babel/types` https://github.com/facebook/react/blob/45804af18d589fd2c181f3b020f07661c46b73ea/compiler/packages/babel-plugin-react-compiler/rollup.config.js#L18) we can move these deps to `devDependencies`. Main motivation is e.g. not installing ancient version of `pretty-format` (asked in https://github.com/facebook/react/issues/29062 without getting a reason, but if consumers can just skip the deps entirely that's even better). ## How did you test this change? I tested by installing the plugin into an empty project, deleting everything in `node_modules` _except_ for `babel-plugin-react-compiler` and doing `require('babel-plugin-react-compiler')`. It still worked fine, so it should work in other cases as well 😀 --- .../babel-plugin-react-compiler/package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/package.json b/compiler/packages/babel-plugin-react-compiler/package.json index 5891ce2b856ad..28f25f927d789 100644 --- a/compiler/packages/babel-plugin-react-compiler/package.json +++ b/compiler/packages/babel-plugin-react-compiler/package.json @@ -18,16 +18,11 @@ "lint": "yarn eslint src" }, "dependencies": { - "@babel/generator": "7.2.0", - "@babel/types": "^7.19.0", - "chalk": "4", - "invariant": "^2.2.4", - "pretty-format": "^24", - "zod": "^3.22.4", - "zod-validation-error": "^2.1.0" + "@babel/types": "^7.19.0" }, "devDependencies": { "@babel/core": "^7.2.0", + "@babel/generator": "7.2.0", "@babel/parser": "^7.2.0", "@babel/plugin-syntax-typescript": "^7.18.6", "@babel/plugin-transform-block-scoping": "^7.18.9", @@ -46,15 +41,20 @@ "babel-jest": "^29.0.3", "babel-plugin-fbt": "^1.0.0", "babel-plugin-fbt-runtime": "^1.0.0", + "chalk": "4", "eslint": "^8.57.1", "glob": "^7.1.6", + "invariant": "^2.2.4", "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", + "pretty-format": "^24", "react": "19.0.0-beta-b498834eab-20240506", "react-dom": "19.0.0-beta-b498834eab-20240506", "rimraf": "^3.0.2", "ts-jest": "^29.1.1", - "ts-node": "^10.9.2" + "ts-node": "^10.9.2", + "zod": "^3.22.4", + "zod-validation-error": "^2.1.0" }, "resolutions": { "./**/@babel/parser": "7.7.4", From 9daabc0bf97805be23f6131be4d84d063a3ff446 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Tue, 22 Oct 2024 23:07:10 +0300 Subject: [PATCH 313/426] `react-hooks/rules-of-hooks`: Add support for `do/while` loops (#28714) ## Summary Currently, `react-hooks/rules-of-hooks` does not support `do/while` loops - I've also reported this in https://github.com/facebook/react/issues/28713. This PR takes a stab at adding support for `do/while` by following the same logic we already have for detecting `while` loops. After this PR, any hooks called inside a `do/while` loop will be considered invalid. We're also adding some unit tests to confirm that the behavior is working as expected. Fixes #28713. ## How did you test this change? I've added unit tests that cover the case and verified that they pass by running: ``` yarn test packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js --watch ``` I've also verified that the rest of the tests continue to pass by running: ``` yarn test ``` and ``` yarn test --prod ``` --- .../__tests__/ESLintRulesOfHooks-test.js | 63 +++++++++++++++++++ .../src/RulesOfHooks.js | 2 +- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js index a1e4c49e15573..4376d01d824a8 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js @@ -755,6 +755,30 @@ const tests = { `, errors: [loopError('useHookInsideLoop')], }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function ComponentWithHookInsideLoop() { + do { + useHookInsideLoop(); + } while (cond); + } + `, + errors: [loopError('useHookInsideLoop')], + }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function ComponentWithHookInsideLoop() { + do { + foo(); + } while (useHookInsideLoop()); + } + `, + errors: [loopError('useHookInsideLoop')], + }, { code: normalizeIndent` // Invalid because it's dangerous and might not warn otherwise. @@ -853,6 +877,45 @@ const tests = { `, errors: [loopError('useHook1'), loopError('useHook2', true)], }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function useHookInLoops() { + do { + useHook1(); + if (a) return; + useHook2(); + } while (b); + + do { + useHook3(); + if (c) return; + useHook4(); + } while (d) + } + `, + errors: [ + loopError('useHook1'), + loopError('useHook2'), + loopError('useHook3'), + loopError('useHook4'), + ], + }, + { + code: normalizeIndent` + // Invalid because it's dangerous and might not warn otherwise. + // This *must* be invalid. + function useHookInLoops() { + do { + useHook1(); + if (a) continue; + useHook2(); + } while (b); + } + `, + errors: [loopError('useHook1'), loopError('useHook2', true)], + }, { code: normalizeIndent` // Invalid because it's dangerous and might not warn otherwise. diff --git a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js index 97e72f01e4ada..0b89390898ef4 100644 --- a/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js +++ b/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js @@ -295,7 +295,7 @@ export default { if (pathList.has(segment.id)) { const pathArray = Array.from(pathList); const cyclicSegments = pathArray.slice( - pathArray.indexOf(segment.id) + 1, + pathArray.indexOf(segment.id) - 1, ); for (const cyclicSegment of cyclicSegments) { cyclic.add(cyclicSegment); From b4cbdc5a7c18672807e119692f99f1cf751242fd Mon Sep 17 00:00:00 2001 From: "Henry Q. Dineen" Date: Tue, 22 Oct 2024 19:49:10 -0400 Subject: [PATCH 314/426] remove terser from react-compiler-runtime build (#31326) ## Summary This fixes a minor nit I have about the `react-compiler-runtime` package in that the published code is minified. I assume most consumers will minify their own bundles so there's no real advantage to minifying it as part of the build. For my purposes it makes it more difficult to read the code, use `patch-package` (if needed), or diff two versions without referencing the source code on github or mapping it back to original source using the source maps. ## How did you test this change? I ran the build locally and looked at the result but did not run the code. It's a lot more readable except for the commonjs compatibility-related stuff that Rollup inserts. --- compiler/packages/react-compiler-runtime/rollup.config.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/packages/react-compiler-runtime/rollup.config.js b/compiler/packages/react-compiler-runtime/rollup.config.js index b98e95bf515ea..260359dd0cd81 100644 --- a/compiler/packages/react-compiler-runtime/rollup.config.js +++ b/compiler/packages/react-compiler-runtime/rollup.config.js @@ -11,7 +11,6 @@ import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; import path from 'path'; import process from 'process'; -import terser from '@rollup/plugin-terser'; import banner2 from 'rollup-plugin-banner2'; const NO_INLINE = new Set(['react']); @@ -37,11 +36,6 @@ const PROD_ROLLUP_CONFIG = { rootDir: path.join(process.cwd(), '..'), }), commonjs(), - terser({ - format: { - comments: false, - }, - }), banner2( () => `/** * Copyright (c) Meta Platforms, Inc. and affiliates. From 2dc5bebd46d5254f9a02fd58d408acb33c288639 Mon Sep 17 00:00:00 2001 From: Hendrik Liebau Date: Wed, 23 Oct 2024 17:36:40 +0200 Subject: [PATCH 315/426] Fix error handling in `resolveClientReference` (#31332) When a React Server Consumer Manifest does not include an entry for a client reference ID, we must not try to look up the export name (or `'*'`) for the client reference. Otherwise this will fail with `TypeError: Cannot read properties of undefined (reading '...')` instead of the custom error we intended to throw. --- .../src/client/ReactFlightClientConfigBundlerNode.js | 6 +++--- .../src/client/ReactFlightClientConfigBundlerTurbopack.js | 6 +++--- .../src/client/ReactFlightClientConfigBundlerNode.js | 6 +++--- .../src/client/ReactFlightClientConfigBundlerWebpack.js | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js index 22321d41d0824..e560275cd1fbd 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerNode.js @@ -62,19 +62,19 @@ export function resolveClientReference( metadata: ClientReferenceMetadata, ): ClientReference { const moduleExports = bundlerConfig[metadata[ID]]; - let resolvedModuleData = moduleExports[metadata[NAME]]; + let resolvedModuleData = moduleExports && moduleExports[metadata[NAME]]; let name; if (resolvedModuleData) { // The potentially aliased name. name = resolvedModuleData.name; } else { // If we don't have this specific name, we might have the full module. - resolvedModuleData = moduleExports['*']; + resolvedModuleData = moduleExports && moduleExports['*']; if (!resolvedModuleData) { throw new Error( 'Could not find the module "' + metadata[ID] + - '" in the React SSR Manifest. ' + + '" in the React Server Consumer Manifest. ' + 'This is probably a bug in the React Server Components bundler.', ); } diff --git a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js index 4ae4a3e365d0c..8cd6804534e0a 100644 --- a/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js +++ b/packages/react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack.js @@ -68,19 +68,19 @@ export function resolveClientReference( ): ClientReference { if (bundlerConfig) { const moduleExports = bundlerConfig[metadata[ID]]; - let resolvedModuleData = moduleExports[metadata[NAME]]; + let resolvedModuleData = moduleExports && moduleExports[metadata[NAME]]; let name; if (resolvedModuleData) { // The potentially aliased name. name = resolvedModuleData.name; } else { // If we don't have this specific name, we might have the full module. - resolvedModuleData = moduleExports['*']; + resolvedModuleData = moduleExports && moduleExports['*']; if (!resolvedModuleData) { throw new Error( 'Could not find the module "' + metadata[ID] + - '" in the React SSR Manifest. ' + + '" in the React Server Consumer Manifest. ' + 'This is probably a bug in the React Server Components bundler.', ); } diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js index 22321d41d0824..e560275cd1fbd 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerNode.js @@ -62,19 +62,19 @@ export function resolveClientReference( metadata: ClientReferenceMetadata, ): ClientReference { const moduleExports = bundlerConfig[metadata[ID]]; - let resolvedModuleData = moduleExports[metadata[NAME]]; + let resolvedModuleData = moduleExports && moduleExports[metadata[NAME]]; let name; if (resolvedModuleData) { // The potentially aliased name. name = resolvedModuleData.name; } else { // If we don't have this specific name, we might have the full module. - resolvedModuleData = moduleExports['*']; + resolvedModuleData = moduleExports && moduleExports['*']; if (!resolvedModuleData) { throw new Error( 'Could not find the module "' + metadata[ID] + - '" in the React SSR Manifest. ' + + '" in the React Server Consumer Manifest. ' + 'This is probably a bug in the React Server Components bundler.', ); } diff --git a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js index e3530021256e3..a43c26ac82bb1 100644 --- a/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js +++ b/packages/react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js @@ -68,19 +68,19 @@ export function resolveClientReference( ): ClientReference { if (bundlerConfig) { const moduleExports = bundlerConfig[metadata[ID]]; - let resolvedModuleData = moduleExports[metadata[NAME]]; + let resolvedModuleData = moduleExports && moduleExports[metadata[NAME]]; let name; if (resolvedModuleData) { // The potentially aliased name. name = resolvedModuleData.name; } else { // If we don't have this specific name, we might have the full module. - resolvedModuleData = moduleExports['*']; + resolvedModuleData = moduleExports && moduleExports['*']; if (!resolvedModuleData) { throw new Error( 'Could not find the module "' + metadata[ID] + - '" in the React SSR Manifest. ' + + '" in the React Server Consumer Manifest. ' + 'This is probably a bug in the React Server Components bundler.', ); } From b3e0a11e8f0689b38a9beec032c0a51cf381e998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 23 Oct 2024 08:38:33 -0700 Subject: [PATCH 316/426] [Flight] Allow stack frames to be serialized if opt-in (#31329) Normally we filter out stack frames with missing `filename` because they can be noisy and not ignore listed. However, it's up to the filterStackFrame function to determine whether to do it. This lets us match `` stack frames in V8 parsing (they don't have line numbers). --- .../react-client/src/ReactFlightClient.js | 2 ++ .../src/__tests__/ReactFlight-test.js | 19 +++++++++++++++++-- .../src/ReactFlightStackConfigV8.js | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index ca0af0206560e..5f49f06e2f234 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -2281,6 +2281,8 @@ function createFakeFunction( code += '\n//# sourceMappingURL=' + sourceMap; } else if (filename) { code += '\n//# sourceURL=' + filename; + } else { + code += '\n//# sourceURL='; } let fn: FakeFunction; diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 92efd84bf0d7a..cd54e4a344f69 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -1282,6 +1282,8 @@ describe('ReactFlight', () => { ' at file:///testing.js:42:3', // async anon function (https://github.com/ChromeDevTools/devtools-frontend/blob/831be28facb4e85de5ee8c1acc4d98dfeda7a73b/test/unittests/front_end/panels/console/ErrorStackParser_test.ts#L130C9-L130C41) ' at async file:///testing.js:42:3', + // host component in parent stack + ' at div ()', ...originalStackLines.slice(2), ].join('\n'); throw error; @@ -1328,6 +1330,15 @@ describe('ReactFlight', () => { } return `digest(${String(x)})`; }, + filterStackFrame(filename, functionName) { + if (!filename) { + // Allow anonymous + return functionName === 'div'; + } + return ( + !filename.startsWith('node:') && !filename.includes('node_modules') + ); + }, }); await act(() => { @@ -1355,14 +1366,16 @@ describe('ReactFlight', () => { ' at eval (eval at testFunction (eval at createFakeFunction (**), :1:35)\n' + ' at ServerComponentError (file://~/(some)(really)(exotic-directory)/ReactFlight-test.js:1166:19)\n' + ' at (file:///testing.js:42:3)\n' + - ' at (file:///testing.js:42:3)\n', + ' at (file:///testing.js:42:3)\n' + + ' at div (', ) : expect.stringContaining( 'Error: This is an error\n' + ' at eval (eval at testFunction (inspected-page.html:29:11), :1:10)\n' + ' at ServerComponentError (file://~/(some)(really)(exotic-directory)/ReactFlight-test.js:1166:19)\n' + ' at file:///testing.js:42:3\n' + - ' at file:///testing.js:42:3', + ' at file:///testing.js:42:3\n' + + ' at div (', ), digest: 'a dev digest', environmentName: 'Server', @@ -1379,6 +1392,7 @@ describe('ReactFlight', () => { 'Server', ], ['file:///testing.js', 'Server'], + ['', 'Server'], [__filename, 'Server'], ] : gate(flags => flags.enableServerComponentLogs) @@ -1390,6 +1404,7 @@ describe('ReactFlight', () => { 'Server', ], ['file:///testing.js', 'Server'], + ['', 'Server'], ] : [], }); diff --git a/packages/react-server/src/ReactFlightStackConfigV8.js b/packages/react-server/src/ReactFlightStackConfigV8.js index 8d43a4aef9403..71465e3c5f536 100644 --- a/packages/react-server/src/ReactFlightStackConfigV8.js +++ b/packages/react-server/src/ReactFlightStackConfigV8.js @@ -44,7 +44,7 @@ function getStack(error: Error): string { // at filename:0:0 // at async filename:0:0 const frameRegExp = - /^ {3} at (?:(.+) \((.+):(\d+):(\d+)\)|(?:async )?(.+):(\d+):(\d+))$/; + /^ {3} at (?:(.+) \((?:(.+):(\d+):(\d+)|\)\)|(?:async )?(.+):(\d+):(\d+)|\)$/; export function parseStackTrace( error: Error, From 28668d39bea855c3bda481d018d8f3f0dfad9066 Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 23 Oct 2024 12:13:22 -0400 Subject: [PATCH 317/426] [playground] Upgrade to Next 15 stable (#31333) --- compiler/apps/playground/package.json | 4 +- compiler/apps/playground/yarn.lock | 130 +++++++++++++------------- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/compiler/apps/playground/package.json b/compiler/apps/playground/package.json index bfdd799d21a59..c3dd825f1a16f 100644 --- a/compiler/apps/playground/package.json +++ b/compiler/apps/playground/package.json @@ -33,7 +33,7 @@ "invariant": "^2.2.4", "lz-string": "^1.5.0", "monaco-editor": "^0.52.0", - "next": "15.0.0-canary.197", + "next": "^15.0.1", "notistack": "^3.0.0-alpha.7", "prettier": "^3.3.3", "pretty-format": "^29.3.1", @@ -49,7 +49,7 @@ "clsx": "^1.2.1", "concurrently": "^7.4.0", "eslint": "^8.28.0", - "eslint-config-next": "15.0.0-canary.197", + "eslint-config-next": "^15.0.1", "monaco-editor-webpack-plugin": "^7.1.0", "postcss": "^8.4.31", "tailwindcss": "^3.2.4", diff --git a/compiler/apps/playground/yarn.lock b/compiler/apps/playground/yarn.lock index 2abe56e8a423c..dc5362548a7f7 100644 --- a/compiler/apps/playground/yarn.lock +++ b/compiler/apps/playground/yarn.lock @@ -589,57 +589,57 @@ dependencies: "@monaco-editor/loader" "^1.4.0" -"@next/env@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.0-canary.197.tgz#d5ae98dab7374d68dcef319f26cd897c0bca16fe" - integrity sha512-xkJbvMANutTqIJ3FPAGtELz5d7ZF/nyNJnpaLAWxV87dF0x8ZVR/uo3MCsrN/jitWfoiEJDav90VeUcYAfhbZA== +"@next/env@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.1.tgz#660fe9303e255cec112d3f4198d2897a24bc60b3" + integrity sha512-lc4HeDUKO9gxxlM5G2knTRifqhsY6yYpwuHspBZdboZe0Gp+rZHBNNSIjmQKDJIdRXiXGyVnSD6gafrbQPvILQ== -"@next/eslint-plugin-next@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.0-canary.197.tgz#2f66f0bc2b81a267e3e424786b9615bb3724bfbd" - integrity sha512-PawKr9jxAjXr8P4p1OtpIX0NyopglQsRG3hDtmZ9RAxNNtheWwIJf3YeaRsXnlf0m8iljAN3MiOZve39GN1FLQ== +"@next/eslint-plugin-next@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.1.tgz#76117d88aadc52f6e04b1892d44654d05468d53c" + integrity sha512-bKWsMaGPbiFAaGqrDJvbE8b4Z0uKicGVcgOI77YM2ui3UfjHMr4emFPrZTLeZVchi7fT1mooG2LxREfUUClIKw== dependencies: fast-glob "3.3.1" -"@next/swc-darwin-arm64@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.0-canary.197.tgz#705f7169b424650a012d8ecb170735211ab818e2" - integrity sha512-WDyzAx/nu1RTg1X27+YNApQLn5cGaCGhOsBuIpPy7U0P+hW2CdZ0YhHprRxA9pIX1CsdvY61BcngkTQOtR3g1w== - -"@next/swc-darwin-x64@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.0-canary.197.tgz#623940d6cbe1c76423ff4e5d3c2ac3cfd3964ce2" - integrity sha512-updImRT6rAV9nhHn8mXW2fYM02JalJt8ogTa3YspHSYtG+ueqdKhXZo+a+YyJ9N/rgLJwtPZnEEZ/SMDbzASvQ== - -"@next/swc-linux-arm64-gnu@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.0-canary.197.tgz#e751ecc349ccfc8ef9689bcabb6c4b405551ffbf" - integrity sha512-FgDBzFwMA/bunjONCwvN0ImmYEqMG4c7544iB6Aj798WF5tGr8hGhSpsjml1EaWq2X3wO3UHtRU5RBUGz+WxGg== - -"@next/swc-linux-arm64-musl@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.0-canary.197.tgz#b7ea38d3dd90040124781d54d8e92fe0eadcf6a0" - integrity sha512-FvNQk7vxPtmesKdR15XoVm8wJUCUXVmbvdwms9f7pXIesdtGvd/eBBQ4e9njU3na1FPrwNzOjV/5DIp8O+ZH0g== - -"@next/swc-linux-x64-gnu@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.0-canary.197.tgz#f9fc075c72caf3e3274cd5fee4d5857b79751b9a" - integrity sha512-cTq5mSGMlYPfn2w3QD6+3kTqqiHrtCfTGfh484Ndmm2EQMUmKafx7s+ovCFMftJoICbQtXCP2ynX/+3GmEF4TQ== - -"@next/swc-linux-x64-musl@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.0-canary.197.tgz#9db818a0f2244ca67f67dddd9f5d31484f481336" - integrity sha512-R/5eZn9u4YwYLid/kUgcFNhON33UxvZN3mbmpxVaZraBGsU+rsXPxl4BSPD070GnH1xwq//3j84I/FfxgwN0kg== - -"@next/swc-win32-arm64-msvc@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.0-canary.197.tgz#263fb82c4dba585d15dfeea681bf38efd8a712a1" - integrity sha512-87P+1a3egZXALB1FB2OMDMp12rUVavuzl3xG9Cqz2aLKxhz+1MD38lKf3W4dsNxJ8lGGygCIeAd1d95aGJybhg== - -"@next/swc-win32-x64-msvc@15.0.0-canary.197": - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.0-canary.197.tgz#bf791a77927ea5adc40f5bf54cb7ed7ac0b75e9f" - integrity sha512-Tw2yrY5FYt08aoz+OKK01kSKaoSfDba3ouwfNoPZnXIGLi/lcKv9ThDpwecj0Qs8cgidNJBba+U52lkkxL94Xw== +"@next/swc-darwin-arm64@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.1.tgz#b80a25f1569bd0ca03eca9473f7e93e64937e404" + integrity sha512-C9k/Xv4sxkQRTA37Z6MzNq3Yb1BJMmSqjmwowoWEpbXTkAdfOwnoKOpAb71ItSzoA26yUTIo6ZhN8rKGu4ExQw== + +"@next/swc-darwin-x64@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.1.tgz#00dcf79ec7c638a85c3b9ff2e2de2bfb09c1c250" + integrity sha512-uHl13HXOuq1G7ovWFxCACDJHTSDVbn/sbLv8V1p+7KIvTrYQ5HNoSmKBdYeEKRRCbEmd+OohOgg9YOp8Ux3MBg== + +"@next/swc-linux-arm64-gnu@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.1.tgz#faab5f7ffcc6d1a15e8dea1cb9953966658b39bf" + integrity sha512-LvyhvxHOihFTEIbb35KxOc3q8w8G4xAAAH/AQnsYDEnOvwawjL2eawsB59AX02ki6LJdgDaHoTEnC54Gw+82xw== + +"@next/swc-linux-arm64-musl@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.1.tgz#97abada9a782ab5b3cb42cf0d4799cbc2e733351" + integrity sha512-vFmCGUFNyk/A5/BYcQNhAQqPIw01RJaK6dRO+ZEhz0DncoW+hJW1kZ8aH2UvTX27zPq3m85zN5waMSbZEmANcQ== + +"@next/swc-linux-x64-gnu@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.1.tgz#548bd47c49fe6d819302139aff8766eb704322e2" + integrity sha512-5by7IYq0NCF8rouz6Qg9T97jYU68kaClHPfGpQG2lCZpSYHtSPQF1kjnqBTd34RIqPKMbCa4DqCufirgr8HM5w== + +"@next/swc-linux-x64-musl@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.1.tgz#84423fbd3a058dd6ae8322e530878f0ec7a1027a" + integrity sha512-lmYr6H3JyDNBJLzklGXLfbehU3ay78a+b6UmBGlHls4xhDXBNZfgb0aI67sflrX+cGBnv1LgmWzFlYrAYxS1Qw== + +"@next/swc-win32-arm64-msvc@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.1.tgz#723c2ced12a998fb40dc901b8faea9170e788c2f" + integrity sha512-DS8wQtl6diAj0eZTdH0sefykm4iXMbHT4MOvLwqZiIkeezKpkgPFcEdFlz3vKvXa2R/2UEgMh48z1nEpNhjeOQ== + +"@next/swc-win32-x64-msvc@15.0.1": + version "15.0.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.1.tgz#ec7e3befc0bcc47527537b1eda2b3745beb15a09" + integrity sha512-4Ho2ggvDdMKlZ/0e9HNdZ9ngeaBwtc+2VS5oCeqrbXqOgutX6I4U2X/42VBw0o+M5evn4/7v3zKgGHo+9v/VjA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1611,12 +1611,12 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-next@15.0.0-canary.197: - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.0.0-canary.197.tgz#06e275c0890f5348be51724dda43a9b2eada12b1" - integrity sha512-YkcBlszYqUwatcuWJzUkJxcb7ztwP6w+/xUKYTRiWhmZTH07YOtG0oHHkWqNqPb0NZ0B65wSKLnZAAPpuLyFGA== +eslint-config-next@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.0.1.tgz#5f49a01d312420cdbf1e87299396ef779ae99004" + integrity sha512-3cYCrgbH6GS/ufApza7XCKz92vtq4dAdYhx++rMFNlH2cAV+/GsAKkrr4+bohYOACmzG2nAOR+uWprKC1Uld6A== dependencies: - "@next/eslint-plugin-next" "15.0.0-canary.197" + "@next/eslint-plugin-next" "15.0.1" "@rushstack/eslint-patch" "^1.10.3" "@typescript-eslint/eslint-plugin" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" "@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" @@ -2682,12 +2682,12 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@15.0.0-canary.197: - version "15.0.0-canary.197" - resolved "https://registry.yarnpkg.com/next/-/next-15.0.0-canary.197.tgz#0b7cf8b6a4a2ba6ca58712ed80709766160510aa" - integrity sha512-13rOJn7FPGmPt+ahDbbiAkJr1qharRbVJVU/pce+T+OGAbZ2kGu0DilJHFYOLEdlmb80+pO+UFHhcMRV4rVm7w== +next@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/next/-/next-15.0.1.tgz#a0e8eda35d803cb7f8092b2a2eb9d072e22bf21d" + integrity sha512-PSkFkr/w7UnFWm+EP8y/QpHrJXMqpZzAXpergB/EqLPOh4SGPJXv1wj4mslr2hUZBAS9pX7/9YLIdxTv6fwytw== dependencies: - "@next/env" "15.0.0-canary.197" + "@next/env" "15.0.1" "@swc/counter" "0.1.3" "@swc/helpers" "0.5.13" busboy "1.6.0" @@ -2695,14 +2695,14 @@ next@15.0.0-canary.197: postcss "8.4.31" styled-jsx "5.1.6" optionalDependencies: - "@next/swc-darwin-arm64" "15.0.0-canary.197" - "@next/swc-darwin-x64" "15.0.0-canary.197" - "@next/swc-linux-arm64-gnu" "15.0.0-canary.197" - "@next/swc-linux-arm64-musl" "15.0.0-canary.197" - "@next/swc-linux-x64-gnu" "15.0.0-canary.197" - "@next/swc-linux-x64-musl" "15.0.0-canary.197" - "@next/swc-win32-arm64-msvc" "15.0.0-canary.197" - "@next/swc-win32-x64-msvc" "15.0.0-canary.197" + "@next/swc-darwin-arm64" "15.0.1" + "@next/swc-darwin-x64" "15.0.1" + "@next/swc-linux-arm64-gnu" "15.0.1" + "@next/swc-linux-arm64-musl" "15.0.1" + "@next/swc-linux-x64-gnu" "15.0.1" + "@next/swc-linux-x64-musl" "15.0.1" + "@next/swc-win32-arm64-msvc" "15.0.1" + "@next/swc-win32-x64-msvc" "15.0.1" sharp "^0.33.5" node-releases@^2.0.18: From 1631855f4303cc8585205307a56c69e3b7248bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 23 Oct 2024 16:29:20 -0700 Subject: [PATCH 318/426] [Flight] encodeURI filenames parsed from stack traces (#31340) When parsing stacks from third parties they may include invalid url characters. So we need to encode them. Since these are expected to be urls though we use just encodeURI instead of encodeURIComponent. --- packages/react-client/src/ReactFlightClient.js | 4 ++-- packages/react-client/src/__tests__/ReactFlight-test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 5f49f06e2f234..0e8fad24823e2 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -2275,12 +2275,12 @@ function createFakeFunction( '\n//# sourceURL=rsc://React/' + encodeURIComponent(environmentName) + '/' + - filename + + encodeURI(filename) + '?' + fakeFunctionIdx++; code += '\n//# sourceMappingURL=' + sourceMap; } else if (filename) { - code += '\n//# sourceURL=' + filename; + code += '\n//# sourceURL=' + encodeURI(filename); } else { code += '\n//# sourceURL='; } diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index cd54e4a344f69..139a75f12982f 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -1363,7 +1363,7 @@ describe('ReactFlight', () => { ) ? expect.stringContaining( 'Error: This is an error\n' + - ' at eval (eval at testFunction (eval at createFakeFunction (**), :1:35)\n' + + ' at eval (eval at testFunction (inspected-page.html:29:11),%20%3Canonymous%3E:1:35)\n' + ' at ServerComponentError (file://~/(some)(really)(exotic-directory)/ReactFlight-test.js:1166:19)\n' + ' at (file:///testing.js:42:3)\n' + ' at (file:///testing.js:42:3)\n' + @@ -1371,7 +1371,7 @@ describe('ReactFlight', () => { ) : expect.stringContaining( 'Error: This is an error\n' + - ' at eval (eval at testFunction (inspected-page.html:29:11), :1:10)\n' + + ' at eval (eval at testFunction (inspected-page.html:29:11),%20%3Canonymous%3E:1:10)\n' + ' at ServerComponentError (file://~/(some)(really)(exotic-directory)/ReactFlight-test.js:1166:19)\n' + ' at file:///testing.js:42:3\n' + ' at file:///testing.js:42:3\n' + From d19ba8ecdd04639630d0ddcf6ed4ce316482a58d Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 24 Oct 2024 20:08:57 +0200 Subject: [PATCH 319/426] [react-compiler-runtime] Support React 17 peer dependency (#31336) ## Summary The recent blog post and [documentation](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18) say that `react-compiler-runtime` supports React 17, yet it currently requires React 18 or 19 as a peer dependency, making it unusable for installing on a project still using React 17. ## How did you test this change? Manually installing the package on a React 17 codebase. --------- Co-authored-by: lauren --- compiler/packages/react-compiler-runtime/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/packages/react-compiler-runtime/package.json b/compiler/packages/react-compiler-runtime/package.json index 9c356a8d274fb..575ec847a5807 100644 --- a/compiler/packages/react-compiler-runtime/package.json +++ b/compiler/packages/react-compiler-runtime/package.json @@ -9,7 +9,7 @@ "src" ], "peerDependencies": { - "react": "^18.2.0 || ^19.0.0" + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "scripts": { "build": "rimraf dist && rollup --config --bundleConfigAsCjs", From cae764ce81b1bd6c418e9e23651794b6b09208e8 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Fri, 25 Oct 2024 09:17:07 -0700 Subject: [PATCH 320/426] Revert "[Re-land] Make prerendering always non-blocking (#31268)" (#31355) This reverts commit 6c4bbc783286bf6eebd9927cb52e8fec5ad4dd74. It looked like the bug we found on the original land was related to broken product code. But through landing #31268 we found additional bugs internally. Since disabling the feature flag does not fix the bugs, we have to revert again to unblock the sync. We can continue to debug with our internal build. --- .../src/__tests__/ReactDOMFiberAsync-test.js | 2 +- .../react-reconciler/src/ReactFiberLane.js | 6 +- .../src/ReactFiberRootScheduler.js | 20 +- .../src/ReactFiberWorkLoop.js | 293 +++++++----------- .../src/__tests__/ReactDeferredValue-test.js | 12 - .../ReactSiblingPrerendering-test.js | 71 ----- 6 files changed, 126 insertions(+), 278 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index 027099d54707c..ee843996bef1c 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -744,7 +744,7 @@ describe('ReactDOMFiberAsync', () => { // Because it suspended, it remains on the current path expect(div.textContent).toBe('/path/a'); }); - assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []); + assertLog([]); await act(async () => { resolvePromise(); diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index b98019046e3c2..7d6bfd16e8aa0 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -765,14 +765,12 @@ export function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didAttemptEntireTree: boolean, + didSkipSuspendedSiblings: boolean, ) { - // TODO: Split this into separate functions for marking the root at the end of - // a render attempt versus suspending while the root is still in progress. root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; - if (enableSiblingPrerendering && didAttemptEntireTree) { + if (enableSiblingPrerendering && !didSkipSuspendedSiblings) { // Mark these lanes as warm so we know there's nothing else to work on. root.warmLanes |= suspendedLanes; } else { diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 39f6f466ed983..9f267e8345e39 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -18,7 +18,6 @@ import { disableSchedulerTimeoutInWorkLoop, enableProfilerTimer, enableProfilerNestedUpdatePhase, - enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import { NoLane, @@ -30,7 +29,6 @@ import { markStarvedLanesAsExpired, claimNextTransitionLane, getNextLanesToFlushSync, - checkIfRootIsPrerendering, } from './ReactFiberLane'; import { CommitContext, @@ -208,10 +206,7 @@ function flushSyncWorkAcrossRoots_impl( ? workInProgressRootRenderLanes : NoLanes, ); - if ( - includesSyncLane(nextLanes) && - !checkIfRootIsPrerendering(root, nextLanes) - ) { + if (includesSyncLane(nextLanes)) { // This root has pending sync work. Flush it now. didPerformSomeWork = true; performSyncWorkOnRoot(root, nextLanes); @@ -346,13 +341,7 @@ function scheduleTaskForRootDuringMicrotask( } // Schedule a new callback in the host environment. - if ( - includesSyncLane(nextLanes) && - // If we're prerendering, then we should use the concurrent work loop - // even if the lanes are synchronous, so that prerendering never blocks - // the main thread. - !(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes)) - ) { + if (includesSyncLane(nextLanes)) { // Synchronous work is always flushed at the end of the microtask, so we // don't need to schedule an additional task. if (existingCallbackNode !== null) { @@ -386,10 +375,9 @@ function scheduleTaskForRootDuringMicrotask( let schedulerPriorityLevel; switch (lanesToEventPriority(nextLanes)) { - // Scheduler does have an "ImmediatePriority", but now that we use - // microtasks for sync work we no longer use that. Any sync work that - // reaches this path is meant to be time sliced. case DiscreteEventPriority: + schedulerPriorityLevel = ImmediateSchedulerPriority; + break; case ContinuousEventPriority: schedulerPriorityLevel = UserBlockingSchedulerPriority; break; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 204776075d49f..aa5884444063d 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -765,12 +765,11 @@ export function scheduleUpdateOnFiber( // The incoming update might unblock the current render. Interrupt the // current attempt and restart from the top. prepareFreshStack(root, NoLanes); - const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); } @@ -833,12 +832,11 @@ export function scheduleUpdateOnFiber( // effect of interrupting the current render and switching to the update. // TODO: Make sure this doesn't override pings that happen while we've // already started rendering. - const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); } } @@ -900,120 +898,100 @@ export function performWorkOnRoot( // for too long ("expired" work, to prevent starvation), or we're in // sync-updates-by-default mode. const shouldTimeSlice = - (!forceSync && - !includesBlockingLane(lanes) && - !includesExpiredLane(root, lanes)) || - // If we're prerendering, then we should use the concurrent work loop - // even if the lanes are synchronous, so that prerendering never blocks - // the main thread. - // TODO: We should consider doing this whenever a sync lane is suspended, - // even for regular pings. - (enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes)); - + !forceSync && + !includesBlockingLane(lanes) && + !includesExpiredLane(root, lanes); let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes, true); + : renderRootSync(root, lanes); - do { + if (exitStatus !== RootInProgress) { let renderWasConcurrent = shouldTimeSlice; - if (exitStatus === RootInProgress) { - // Render phase is still in progress. - if ( - enableSiblingPrerendering && - workInProgressRootIsPrerendering && - !shouldTimeSlice - ) { - // We're in prerendering mode, but time slicing is not enabled. This - // happens when something suspends during a synchronous update. Exit the - // the work loop. When we resume, we'll use the concurrent work loop so - // that prerendering is non-blocking. - // - // Mark the root as suspended. Usually we do this at the end of the - // render phase, but we do it here so that we resume in - // prerendering mode. - // TODO: Consider always calling markRootSuspended immediately. - // Needs to be *after* we attach a ping listener, though. - const didAttemptEntireTree = false; - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); - } - break; - } else if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings; - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); - } else { - // The render completed. - - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - const finishedWork: Fiber = (root.current.alternate: any); - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes, false); - // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - renderWasConcurrent = false; - // Need to check the exit status again. - continue; - } - - // Check if something threw - if ( - (disableLegacyMode || root.tag !== LegacyRoot) && - exitStatus === RootErrored - ) { - const lanesThatJustErrored = lanes; - const errorRetryLanes = getLanesToRetrySynchronouslyOnError( + do { + if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + markRootSuspended( root, - lanesThatJustErrored, + lanes, + NoLane, + workInProgressRootDidSkipSuspendedSiblings, ); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( + } else { + // The render completed. + + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + const finishedWork: Fiber = (root.current.alternate: any); + if ( + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) + ) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); + // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + renderWasConcurrent = false; + // Need to check the exit status again. + continue; + } + + // Check if something threw + if ( + (disableLegacyMode || root.tag !== LegacyRoot) && + exitStatus === RootErrored + ) { + const lanesThatJustErrored = lanes; + const errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, lanesThatJustErrored, - errorRetryLanes, ); - renderWasConcurrent = false; - // Need to check the exit status again. - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } else { - // The root errored yet again. Proceed to commit the tree. + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + lanesThatJustErrored, + errorRetryLanes, + ); + renderWasConcurrent = false; + // Need to check the exit status again. + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; + } else { + // The root errored yet again. Proceed to commit the tree. + } } } - } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - // Since this is a fatal error, we're going to pretend we attempted - // the entire tree, to avoid scheduling a prerender. - const didAttemptEntireTree = true; - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); - break; - } + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended( + root, + lanes, + NoLane, + workInProgressRootDidSkipSuspendedSiblings, + ); + break; + } - // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. - finishConcurrentRender(root, exitStatus, finishedWork, lanes); - } - break; - } while (true); + // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } + break; + } while (true); + } ensureRootIsScheduled(root); } @@ -1046,7 +1024,7 @@ function recoverFromConcurrentError( rootWorkInProgress.flags |= ForceClientRender; } - const exitStatus = renderRootSync(root, errorRetryLanes, false); + const exitStatus = renderRootSync(root, errorRetryLanes); if (exitStatus !== RootErrored) { // Successfully finished rendering on retry @@ -1130,13 +1108,11 @@ function finishConcurrentRender( // This is a transition, so we should exit without committing a // placeholder and without scheduling a timeout. Delay indefinitely // until we receive more data. - const didAttemptEntireTree = - !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); return; } @@ -1192,13 +1168,11 @@ function finishConcurrentRender( // Don't bother with a very short suspense time. if (msUntilTimeout > 10) { - const didAttemptEntireTree = - !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); const nextLanes = getNextLanes(root, NoLanes); @@ -1312,8 +1286,7 @@ function commitRootWhenReady( completedRenderEndTime, ), ); - const didAttemptEntireTree = !didSkipSuspendedSiblings; - markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree); + markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings); return; } } @@ -1436,7 +1409,7 @@ function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didAttemptEntireTree: boolean, + didSkipSuspendedSiblings: boolean, ) { // When suspending, we should always exclude lanes that were pinged or (more // rarely, since we try to avoid it) updated during the render phase. @@ -1445,7 +1418,12 @@ function markRootSuspended( suspendedLanes, workInProgressRootInterleavedUpdatedLanes, ); - _markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree); + _markRootSuspended( + root, + suspendedLanes, + spawnedLane, + didSkipSuspendedSiblings, + ); } export function flushRoot(root: FiberRoot, lanes: Lanes) { @@ -1987,12 +1965,7 @@ export function renderDidSuspendDelayIfPossible(): void { if ( !workInProgressRootDidSkipSuspendedSiblings && - // Check if the root will be blocked from committing. - // TODO: Consider aligning this better with the rest of the logic. Maybe - // we should only set the exit status to RootSuspendedWithDelay if this - // condition is true? And remove the equivalent checks elsewhere. - (includesOnlyTransitions(workInProgressRootRenderLanes) || - getSuspenseHandler() === null) + !includesBlockingLane(workInProgressRootRenderLanes) ) { // This render may not have originally been scheduled as a prerender, but // something suspended inside the visible part of the tree, which means we @@ -2018,12 +1991,11 @@ export function renderDidSuspendDelayIfPossible(): void { // pinged or updated while we were rendering. // TODO: Consider unwinding immediately, using the // SuspendedOnHydration mechanism. - const didAttemptEntireTree = false; markRootSuspended( workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); } } @@ -2053,11 +2025,7 @@ export function renderHasNotSuspendedYet(): boolean { // TODO: Over time, this function and renderRootConcurrent have become more // and more similar. Not sure it makes sense to maintain forked paths. Consider // unifying them again. -function renderRootSync( - root: FiberRoot, - lanes: Lanes, - shouldYieldForPrerendering: boolean, -): RootExitStatus { +function renderRootSync(root: FiberRoot, lanes: Lanes) { const prevExecutionContext = executionContext; executionContext |= RenderContext; const prevDispatcher = pushDispatcher(root.containerInfo); @@ -2097,7 +2065,6 @@ function renderRootSync( } let didSuspendInShell = false; - let exitStatus = workInProgressRootExitStatus; outer: do { try { if ( @@ -2119,37 +2086,16 @@ function renderRootSync( // Selective hydration. An update flowed into a dehydrated tree. // Interrupt the current render so the work loop can switch to the // hydration lane. - // TODO: I think we might not need to reset the stack here; we can - // just yield and reset the stack when we re-enter the work loop, - // like normal. resetWorkInProgressStack(); - exitStatus = RootDidNotComplete; + workInProgressRootExitStatus = RootDidNotComplete; break outer; } case SuspendedOnImmediate: - case SuspendedOnData: - case SuspendedOnDeprecatedThrowPromise: { - if (getSuspenseHandler() === null) { + case SuspendedOnData: { + if (!didSuspendInShell && getSuspenseHandler() === null) { didSuspendInShell = true; } - const reason = workInProgressSuspendedReason; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason); - if ( - enableSiblingPrerendering && - shouldYieldForPrerendering && - workInProgressRootIsPrerendering - ) { - // We've switched into prerendering mode. This implies that we - // suspended outside of a Suspense boundary, which means this - // render will be blocked from committing. Yield to the main - // thread so we can switch to prerendering using the concurrent - // work loop. - exitStatus = RootInProgress; - break outer; - } - break; + // Intentional fallthrough } default: { // Unwind then continue with the normal work loop. @@ -2162,7 +2108,6 @@ function renderRootSync( } } workLoopSync(); - exitStatus = workInProgressRootExitStatus; break; } catch (thrownValue) { handleThrow(root, thrownValue); @@ -2185,6 +2130,14 @@ function renderRootSync( popDispatcher(prevDispatcher); popAsyncDispatcher(prevAsyncDispatcher); + if (workInProgress !== null) { + // This is a sync render, so we should have finished the whole tree. + throw new Error( + 'Cannot commit an incomplete root. This error is likely caused by a ' + + 'bug in React. Please file an issue.', + ); + } + if (__DEV__) { if (enableDebugTracing) { logRenderStopped(); @@ -2195,21 +2148,14 @@ function renderRootSync( markRenderStopped(); } - if (workInProgress !== null) { - // Did not complete the tree. This can happen if something suspended in - // the shell. - } else { - // Normal case. We completed the whole tree. - - // Set this to null to indicate there's no in-progress render. - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; - // It's safe to process the queue now that the render phase is complete. - finishQueueingConcurrentUpdates(); - } + // It's safe to process the queue now that the render phase is complete. + finishQueueingConcurrentUpdates(); - return exitStatus; + return workInProgressRootExitStatus; } // The work loop is an extremely hot path. Tell Closure not to inline it. @@ -2255,7 +2201,9 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) { // // If we were previously in prerendering mode, check if we received any new // data during an interleaved event. - workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); + if (workInProgressRootIsPrerendering) { + workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); + } } if (__DEV__) { @@ -3805,9 +3753,6 @@ function pingSuspendedRoot( // the logic of whether or not a root suspends once it completes. // TODO: If we're rendering sync either due to Sync, Batched or expired, // we should probably never restart. - // TODO: Attach different listeners depending on whether the listener was - // attached during prerendering. Prerender pings should not interrupt - // normal renders. // If we're suspended with delay, or if it's a retry, we'll always suspend // so we can always restart. diff --git a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js index 8ca142cb50517..fd03ba7310f83 100644 --- a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js +++ b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js @@ -420,10 +420,6 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', - - ...(gate('enableSiblingPrerendering') - ? ['Suspend! [Loading...]', 'Suspend! [Final]'] - : []), ]); expect(root).toMatchRenderedOutput(null); @@ -463,10 +459,6 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', - - ...(gate('enableSiblingPrerendering') - ? ['Suspend! [Loading...]', 'Suspend! [Final]'] - : []), ]); expect(root).toMatchRenderedOutput(null); @@ -541,10 +533,6 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', - - ...(gate('enableSiblingPrerendering') - ? ['Suspend! [Loading...]', 'Suspend! [Final]'] - : []), ]); expect(root).toMatchRenderedOutput(null); diff --git a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js index 235e8df2201de..37d907b0fdc65 100644 --- a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js @@ -479,75 +479,4 @@ describe('ReactSiblingPrerendering', () => { assertLog([]); }, ); - - it( - 'when a synchronous update suspends outside a boundary, the resulting' + - 'prerender is concurrent', - async () => { - function App() { - return ( - <> - - - - - - - ); - } - - const root = ReactNoop.createRoot(); - // Mount the root synchronously - ReactNoop.flushSync(() => root.render()); - - // Synchronously render everything until we suspend in the shell - assertLog(['A', 'B', 'Suspend! [Async]']); - - if (gate('enableSiblingPrerendering')) { - // The rest of the siblings begin to prerender concurrently. Notice - // that we don't unwind here; we pick up where we left off above. - await waitFor(['C']); - await waitFor(['D']); - } - - assertLog([]); - expect(root).toMatchRenderedOutput(null); - - await resolveText('Async'); - assertLog(['A', 'B', 'Async', 'C', 'D']); - expect(root).toMatchRenderedOutput('ABAsyncCD'); - }, - ); - - it('restart a suspended sync render if something suspends while prerendering the siblings', async () => { - function App() { - return ( - <> - - - - - - - ); - } - - const root = ReactNoop.createRoot(); - // Mount the root synchronously - ReactNoop.flushSync(() => root.render()); - - // Synchronously render everything until we suspend in the shell - assertLog(['A', 'B', 'Suspend! [Async]']); - - if (gate('enableSiblingPrerendering')) { - // The rest of the siblings begin to prerender concurrently - await waitFor(['C']); - } - - // While we're prerendering, Async resolves. We should unwind and - // start over, rather than continue prerendering D. - await resolveText('Async'); - assertLog(['A', 'B', 'Async', 'C', 'D']); - expect(root).toMatchRenderedOutput('ABAsyncCD'); - }); }); From fe04dbcbc4185d7c9d7afebbe18589d2b681a88c Mon Sep 17 00:00:00 2001 From: Mike Vitousek Date: Fri, 25 Oct 2024 16:47:19 -0700 Subject: [PATCH 321/426] [compiler] Fix to ref access check to ban ref?.current ghstack-source-id: ea417a468eac2607ce8d1dddcb2e9581e1c4db27 Pull Request resolved: https://github.com/facebook/react/pull/31360 --- .../Validation/ValidateNoRefAccesInRender.ts | 22 +++++++++---- .../compiler/error.ref-optional.expect.md | 32 +++++++++++++++++++ .../fixtures/compiler/error.ref-optional.js | 11 +++++++ 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts index efc8211f937b7..b361b2016a1dd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Validation/ValidateNoRefAccesInRender.ts @@ -214,16 +214,24 @@ function joinRefAccessTypes(...types: Array): RefAccessType { return b; } else if (b.kind === 'None') { return a; - } else if (a.kind === 'Guard' || b.kind === 'Guard') { - if (a.kind === 'Guard' && b.kind === 'Guard' && a.refId === b.refId) { + } else if (a.kind === 'Guard') { + if (b.kind === 'Guard' && a.refId === b.refId) { return a; + } else if (b.kind === 'Nullable' || b.kind === 'Guard') { + return {kind: 'None'}; + } else { + return b; } - return {kind: 'None'}; - } else if (a.kind === 'Nullable' || b.kind === 'Nullable') { - if (a.kind === 'Nullable' && b.kind === 'Nullable') { - return a; + } else if (b.kind === 'Guard') { + if (a.kind === 'Nullable') { + return {kind: 'None'}; + } else { + return b; } - return {kind: 'None'}; + } else if (a.kind === 'Nullable') { + return b; + } else if (b.kind === 'Nullable') { + return a; } else { return joinRefAccessRefTypes(a, b); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md new file mode 100644 index 0000000000000..1d1a30acafb5c --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.expect.md @@ -0,0 +1,32 @@ + +## Input + +```javascript +import {useRef} from 'react'; + +function Component(props) { + const ref = useRef(); + return ref?.current; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; + +``` + + +## Error + +``` + 3 | function Component(props) { + 4 | const ref = useRef(); +> 5 | return ref?.current; + | ^^^^^^^^^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (5:5) + 6 | } + 7 | + 8 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.js new file mode 100644 index 0000000000000..00c67037b8642 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.ref-optional.js @@ -0,0 +1,11 @@ +import {useRef} from 'react'; + +function Component(props) { + const ref = useRef(); + return ref?.current; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [], +}; From aded0ef831e100a5ee9d9e674cb0482326279118 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Mon, 28 Oct 2024 13:10:01 +0000 Subject: [PATCH 322/426] [compiler] Handle member expr as computed property (#31344) This PR loosens the restriction on the types of computed properties we can handle. Previously, we would disallow anything that is not an identifier because non-identifiers could be mutating. But member expressions are not mutating so we can treat them similar to identifiers. --- .../src/HIR/BuildHIR.ts | 2 +- ...ject-expression-member-expr-call.expect.md | 37 +++++++++++++ ...todo-object-expression-member-expr-call.js | 16 ++++++ ...bject-expression-computed-member.expect.md | 53 +++++++++++++++++++ .../object-expression-computed-member.js | 15 ++++++ 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts index a179224a7705f..9494436d1f463 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts @@ -1418,7 +1418,7 @@ function lowerObjectPropertyKey( name: key.node.value, }; } else if (property.node.computed && key.isExpression()) { - if (!key.isIdentifier()) { + if (!key.isIdentifier() && !key.isMemberExpression()) { /* * NOTE: allowing complex key expressions can trigger a bug where a mutation is made conditional * see fixture diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md new file mode 100644 index 0000000000000..82d9ca17ec2a2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.expect.md @@ -0,0 +1,37 @@ + +## 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 + +``` + 5 | const key = {}; + 6 | const context = { +> 7 | [obj.mutateAndReturn(key)]: identity([props.value]), + | ^^^^^^^^^^^^^^^^^^^^^^^^ Todo: (BuildHIR::lowerExpression) Expected Identifier, got CallExpression key in ObjectExpression (7:7) + 8 | }; + 9 | mutate(key); + 10 | return context; +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js new file mode 100644 index 0000000000000..5cef590ed5dab --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-object-expression-member-expr-call.js @@ -0,0 +1,16 @@ +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}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md new file mode 100644 index 0000000000000..810b03e529e77 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.expect.md @@ -0,0 +1,53 @@ + +## Input + +```javascript +import {identity, mutate, mutateAndReturn} from 'shared-runtime'; + +function Component(props) { + const key = {a: 'key'}; + const context = { + [key.a]: 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 key = { a: "key" }; + context = { [key.a]: 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) {"key":[42]} \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.js new file mode 100644 index 0000000000000..95a1d434624e9 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-expression-computed-member.js @@ -0,0 +1,15 @@ +import {identity, mutate, mutateAndReturn} from 'shared-runtime'; + +function Component(props) { + const key = {a: 'key'}; + const context = { + [key.a]: identity([props.value]), + }; + mutate(key); + return context; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{value: 42}], +}; From 02c0e824e462c7f81ba79d95cfc41c89c6d81b95 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Mon, 28 Oct 2024 15:08:27 +0000 Subject: [PATCH 323/426] [compiler][ez] Remove unused param (#31376) --- .../src/Optimization/ConstantPropagation.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts index 24498012a08eb..a9f62c1986efa 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/ConstantPropagation.ts @@ -8,7 +8,6 @@ import {isValidIdentifier} from '@babel/types'; import {CompilerError} from '../CompilerError'; import { - Environment, GotoVariant, HIRFunction, IdentifierId, @@ -130,7 +129,7 @@ function applyConstantPropagation( continue; } const instr = block.instructions[i]!; - const value = evaluateInstruction(fn.env, constants, instr); + const value = evaluateInstruction(constants, instr); if (value !== null) { constants.set(instr.lvalue.identifier.id, value); } @@ -223,7 +222,6 @@ function evaluatePhi(phi: Phi, constants: Constants): Constant | null { } function evaluateInstruction( - env: Environment, constants: Constants, instr: Instruction, ): Constant | null { From 0bc30748730063e561d87a24a4617526fdd38349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Mon, 28 Oct 2024 13:59:38 -0700 Subject: [PATCH 324/426] Capture the source and not just the stack on first seen error (#31367) Otherwise we can't capture the owner stack at the right location when there's a rethrow. --- .../src/createReactNoop.js | 10 ++- .../src/ReactCapturedValue.js | 40 +++++----- .../src/__tests__/ReactErrorStacks-test.js | 73 +++++++++++++++++++ 3 files changed, 102 insertions(+), 21 deletions(-) diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 55e0fd24c9b9b..b9454b8ec2339 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -81,6 +81,8 @@ type TextInstance = { type HostContext = Object; type CreateRootOptions = { unstable_transitionCallbacks?: TransitionTracingCallbacks, + onUncaughtError?: (error: mixed, errorInfo: {componentStack: string}) => void, + onCaughtError?: (error: mixed, errorInfo: {componentStack: string}) => void, ... }; @@ -1069,8 +1071,12 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { null, false, '', - NoopRenderer.defaultOnUncaughtError, - NoopRenderer.defaultOnCaughtError, + options && options.onUncaughtError + ? options.onUncaughtError + : NoopRenderer.defaultOnUncaughtError, + options && options.onCaughtError + ? options.onCaughtError + : NoopRenderer.defaultOnCaughtError, onRecoverableError, options && options.unstable_transitionCallbacks ? options.unstable_transitionCallbacks diff --git a/packages/react-reconciler/src/ReactCapturedValue.js b/packages/react-reconciler/src/ReactCapturedValue.js index 6ac8e235ccc04..c1c5822bebe26 100644 --- a/packages/react-reconciler/src/ReactCapturedValue.js +++ b/packages/react-reconciler/src/ReactCapturedValue.js @@ -11,7 +11,7 @@ import type {Fiber} from './ReactInternalTypes'; import {getStackByFiberInDevAndProd} from './ReactFiberComponentStack'; -const CapturedStacks: WeakMap = new WeakMap(); +const CapturedStacks: WeakMap> = new WeakMap(); export type CapturedValue<+T> = { +value: T, @@ -25,36 +25,38 @@ export function createCapturedValueAtFiber( ): CapturedValue { // If the value is an error, call this function immediately after it is thrown // so the stack is accurate. - let stack; if (typeof value === 'object' && value !== null) { - const capturedStack = CapturedStacks.get(value); - if (typeof capturedStack === 'string') { - stack = capturedStack; - } else { - stack = getStackByFiberInDevAndProd(source); - CapturedStacks.set(value, stack); + const existing = CapturedStacks.get(value); + if (existing !== undefined) { + return existing; } + const captured = { + value, + source, + stack: getStackByFiberInDevAndProd(source), + }; + CapturedStacks.set(value, captured); + return captured; } else { - stack = getStackByFiberInDevAndProd(source); + return { + value, + source, + stack: getStackByFiberInDevAndProd(source), + }; } - - return { - value, - source, - stack, - }; } export function createCapturedValueFromError( value: Error, stack: null | string, ): CapturedValue { - if (typeof stack === 'string') { - CapturedStacks.set(value, stack); - } - return { + const captured = { value, source: null, stack: stack, }; + if (typeof stack === 'string') { + CapturedStacks.set(value, captured); + } + return captured; } diff --git a/packages/react-reconciler/src/__tests__/ReactErrorStacks-test.js b/packages/react-reconciler/src/__tests__/ReactErrorStacks-test.js index 6e6a9d471c4ef..3098dacfedfd4 100644 --- a/packages/react-reconciler/src/__tests__/ReactErrorStacks-test.js +++ b/packages/react-reconciler/src/__tests__/ReactErrorStacks-test.js @@ -100,4 +100,77 @@ describe('ReactFragment', () => { ]), ]); }); + + it('retains owner stacks when rethrowing an error', async () => { + function Foo() { + return ( + + + + ); + } + function Bar() { + return ; + } + function SomethingThatErrors() { + throw new Error('uh oh'); + } + + class RethrowingBoundary extends React.Component { + static getDerivedStateFromError(error) { + throw error; + } + + render() { + return this.props.children; + } + } + + const errors = []; + class CatchingBoundary extends React.Component { + constructor() { + super(); + this.state = {}; + } + static getDerivedStateFromError(error) { + return {errored: true}; + } + render() { + if (this.state.errored) { + return null; + } + return this.props.children; + } + } + + ReactNoop.createRoot({ + onCaughtError(error, errorInfo) { + errors.push( + error.message, + normalizeCodeLocInfo(errorInfo.componentStack), + React.captureOwnerStack + ? normalizeCodeLocInfo(React.captureOwnerStack()) + : null, + ); + }, + }).render( + + + , + ); + await waitForAll([]); + expect(errors).toEqual([ + 'uh oh', + componentStack([ + 'SomethingThatErrors', + 'Bar', + 'RethrowingBoundary', + 'Foo', + 'CatchingBoundary', + ]), + gate(flags => flags.enableOwnerStacks) && __DEV__ + ? componentStack(['Bar', 'Foo']) + : null, + ]); + }); }); From 3928cb00db94e31afd3efa6850f0e8bec53aefc1 Mon Sep 17 00:00:00 2001 From: lauren Date: Tue, 29 Oct 2024 21:36:36 -0400 Subject: [PATCH 325/426] [compiler] Ref validation repro for ImportSpecifier with renamed local (#31383) This was originally reported in https://github.com/reactwg/react-compiler/discussions/27. Adding a failing repro to capture this case. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31383). * #31385 * #31384 * __->__ #31383 --- .../error.bug-import-as-local.expect.md | 71 +++++++++++++++++++ .../compiler/error.bug-import-as-local.tsx | 42 +++++++++++ 2 files changed, 113 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md new file mode 100644 index 0000000000000..f909d7d2c8476 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md @@ -0,0 +1,71 @@ + +## Input + +```javascript +import { + useEffect, + useRef, + // @ts-expect-error + experimental_useEffectEvent as useEffectEvent, +} from 'react'; + +let id = 0; +function uniqueId() { + 'use no memo'; + return id++; +} + +export function useCustomHook(src: string): void { + const uidRef = useRef(uniqueId()); + const destroyed = useRef(false); + const getItem = (srcName, uid) => { + return {srcName, uid}; + }; + + const getItemEvent = useEffectEvent(() => { + if (destroyed.current) return; + + getItem(src, uidRef.current); + }); + + useEffect(() => { + destroyed.current = false; + getItemEvent(); + }, []); +} + +function Component() { + useCustomHook('hello'); + return

Hello
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + isComponent: true, + params: [{x: 1}], +}; + +``` + + +## Error + +``` + 19 | }; + 20 | +> 21 | const getItemEvent = useEffectEvent(() => { + | ^^^^^^^ +> 22 | if (destroyed.current) return; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 23 | + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 24 | getItem(src, uidRef.current); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +> 25 | }); + | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (21:25) + 26 | + 27 | useEffect(() => { + 28 | destroyed.current = false; +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx new file mode 100644 index 0000000000000..a1c7220f29058 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx @@ -0,0 +1,42 @@ +import { + useEffect, + useRef, + // @ts-expect-error + experimental_useEffectEvent as useEffectEvent, +} from 'react'; + +let id = 0; +function uniqueId() { + 'use no memo'; + return id++; +} + +export function useCustomHook(src: string): void { + const uidRef = useRef(uniqueId()); + const destroyed = useRef(false); + const getItem = (srcName, uid) => { + return {srcName, uid}; + }; + + const getItemEvent = useEffectEvent(() => { + if (destroyed.current) return; + + getItem(src, uidRef.current); + }); + + useEffect(() => { + destroyed.current = false; + getItemEvent(); + }, []); +} + +function Component() { + useCustomHook('hello'); + return
Hello
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + isComponent: true, + params: [{x: 1}], +}; From 4abe4b582106f2012f4eb9624a10f77d167cc848 Mon Sep 17 00:00:00 2001 From: lauren Date: Tue, 29 Oct 2024 21:36:48 -0400 Subject: [PATCH 326/426] [compiler] Check if local identifier is a hook when resolving globals (#31384) When resolving import specifiers from the react namespace (`import {imported as local} from 'react'`), we were previously only checking if the `imported` identifier was a hook if we didn't already have its definition in the global registry. We also need to check if `local` is a hook in the case of aliasing since there may be hook-like APIs in react that don't start with `use` (eg they are experimental or unstable). --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31384). * #31385 * __->__ #31384 * #31383 --- .../src/HIR/Environment.ts | 4 +- .../compiler/import-as-local.expect.md | 140 ++++++++++++++++++ .../fixtures/compiler/import-as-local.tsx | 42 ++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index b85d9425cb7ac..c2918121d2afd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -852,7 +852,9 @@ export class Environment { */ return ( this.#globals.get(binding.imported) ?? - (isHookName(binding.imported) ? this.#getCustomHookType() : null) + (isHookName(binding.imported) || isHookName(binding.name) + ? this.#getCustomHookType() + : null) ); } else { const moduleType = this.#resolveModuleType(binding.module, loc); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md new file mode 100644 index 0000000000000..fea502d0d3bfe --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md @@ -0,0 +1,140 @@ + +## Input + +```javascript +import { + useEffect, + useRef, + // @ts-expect-error + experimental_useEffectEvent as useEffectEvent, +} from 'react'; + +let id = 0; +function uniqueId() { + 'use no memo'; + return id++; +} + +export function useCustomHook(src: string): void { + const uidRef = useRef(uniqueId()); + const destroyed = useRef(false); + const getItem = (srcName, uid) => { + return {srcName, uid}; + }; + + const getItemEvent = useEffectEvent(() => { + if (destroyed.current) return; + + getItem(src, uidRef.current); + }); + + useEffect(() => { + destroyed.current = false; + getItemEvent(); + }, []); +} + +function Component() { + useCustomHook('hello'); + return
Hello
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + isComponent: true, + params: [{x: 1}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { + useEffect, + useRef, + // @ts-expect-error + experimental_useEffectEvent as useEffectEvent, +} from "react"; + +let id = 0; +function uniqueId() { + "use no memo"; + return id++; +} + +export function useCustomHook(src) { + const $ = _c(6); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 = uniqueId(); + $[0] = t0; + } else { + t0 = $[0]; + } + const uidRef = useRef(t0); + const destroyed = useRef(false); + const getItem = _temp; + let t1; + if ($[1] !== src) { + t1 = () => { + if (destroyed.current) { + return; + } + + getItem(src, uidRef.current); + }; + $[1] = src; + $[2] = t1; + } else { + t1 = $[2]; + } + const getItemEvent = useEffectEvent(t1); + let t2; + if ($[3] !== getItemEvent) { + t2 = () => { + destroyed.current = false; + getItemEvent(); + }; + $[3] = getItemEvent; + $[4] = t2; + } else { + t2 = $[4]; + } + let t3; + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { + t3 = []; + $[5] = t3; + } else { + t3 = $[5]; + } + useEffect(t2, t3); +} +function _temp(srcName, uid) { + return { srcName, uid }; +} + +function Component() { + const $ = _c(1); + useCustomHook("hello"); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + isComponent: true, + params: [{ x: 1 }], +}; + +``` + +### Eval output +(kind: exception) (0 , _react.experimental_useEffectEvent) is not a function \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.tsx new file mode 100644 index 0000000000000..a1c7220f29058 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.tsx @@ -0,0 +1,42 @@ +import { + useEffect, + useRef, + // @ts-expect-error + experimental_useEffectEvent as useEffectEvent, +} from 'react'; + +let id = 0; +function uniqueId() { + 'use no memo'; + return id++; +} + +export function useCustomHook(src: string): void { + const uidRef = useRef(uniqueId()); + const destroyed = useRef(false); + const getItem = (srcName, uid) => { + return {srcName, uid}; + }; + + const getItemEvent = useEffectEvent(() => { + if (destroyed.current) return; + + getItem(src, uidRef.current); + }); + + useEffect(() => { + destroyed.current = false; + getItemEvent(); + }, []); +} + +function Component() { + useCustomHook('hello'); + return
Hello
; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + isComponent: true, + params: [{x: 1}], +}; From 603e6108f39c6663ec703eed34a89ff1bf0cb70c Mon Sep 17 00:00:00 2001 From: lauren Date: Tue, 29 Oct 2024 21:51:41 -0400 Subject: [PATCH 327/426] [compiler] Update react deps to experimental instead of beta (#31385) Some tests rely on experimental APIs so let's just use react@experimental instead of beta --- .../babel-plugin-react-compiler/package.json | 4 +- .../error.bug-import-as-local.expect.md | 71 ----- .../compiler/error.bug-import-as-local.tsx | 42 --- .../fbt-preserve-whitespace-subtree.expect.md | 4 +- .../fbt/fbt-preserve-whitespace-subtree.tsx | 2 +- ...preserve-whitespace-two-subtrees.expect.md | 8 +- .../fbt-preserve-whitespace-two-subtrees.tsx | 4 +- .../compiler/import-as-local.expect.md | 2 +- .../compiler/module-scoped-bindings.expect.md | 2 +- compiler/packages/snap/package.json | 4 +- compiler/yarn.lock | 264 ++++++++++-------- 11 files changed, 167 insertions(+), 240 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/package.json b/compiler/packages/babel-plugin-react-compiler/package.json index 28f25f927d789..2e7013577c9a3 100644 --- a/compiler/packages/babel-plugin-react-compiler/package.json +++ b/compiler/packages/babel-plugin-react-compiler/package.json @@ -48,8 +48,8 @@ "jest": "^29.0.3", "jest-environment-jsdom": "^29.0.3", "pretty-format": "^24", - "react": "19.0.0-beta-b498834eab-20240506", - "react-dom": "19.0.0-beta-b498834eab-20240506", + "react": "0.0.0-experimental-0bc30748-20241028", + "react-dom": "0.0.0-experimental-0bc30748-20241028", "rimraf": "^3.0.2", "ts-jest": "^29.1.1", "ts-node": "^10.9.2", diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md deleted file mode 100644 index f909d7d2c8476..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.expect.md +++ /dev/null @@ -1,71 +0,0 @@ - -## Input - -```javascript -import { - useEffect, - useRef, - // @ts-expect-error - experimental_useEffectEvent as useEffectEvent, -} from 'react'; - -let id = 0; -function uniqueId() { - 'use no memo'; - return id++; -} - -export function useCustomHook(src: string): void { - const uidRef = useRef(uniqueId()); - const destroyed = useRef(false); - const getItem = (srcName, uid) => { - return {srcName, uid}; - }; - - const getItemEvent = useEffectEvent(() => { - if (destroyed.current) return; - - getItem(src, uidRef.current); - }); - - useEffect(() => { - destroyed.current = false; - getItemEvent(); - }, []); -} - -function Component() { - useCustomHook('hello'); - return
Hello
; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - isComponent: true, - params: [{x: 1}], -}; - -``` - - -## Error - -``` - 19 | }; - 20 | -> 21 | const getItemEvent = useEffectEvent(() => { - | ^^^^^^^ -> 22 | if (destroyed.current) return; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 23 | - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 24 | getItem(src, uidRef.current); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -> 25 | }); - | ^^^^ InvalidReact: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef) (21:25) - 26 | - 27 | useEffect(() => { - 28 | destroyed.current = false; -``` - - \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx deleted file mode 100644 index a1c7220f29058..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.bug-import-as-local.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - useEffect, - useRef, - // @ts-expect-error - experimental_useEffectEvent as useEffectEvent, -} from 'react'; - -let id = 0; -function uniqueId() { - 'use no memo'; - return id++; -} - -export function useCustomHook(src: string): void { - const uidRef = useRef(uniqueId()); - const destroyed = useRef(false); - const getItem = (srcName, uid) => { - return {srcName, uid}; - }; - - const getItemEvent = useEffectEvent(() => { - if (destroyed.current) return; - - getItem(src, uidRef.current); - }); - - useEffect(() => { - destroyed.current = false; - getItemEvent(); - }, []); -} - -function Component() { - useCustomHook('hello'); - return
Hello
; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - isComponent: true, - params: [{x: 1}], -}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.expect.md index e4e16a9e1d014..702a9fd8eabe3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.expect.md @@ -14,7 +14,7 @@ import fbt from 'fbt'; function Foo(props) { return ( - + {props.name} @@ -53,7 +53,7 @@ function Foo(props) { [ fbt._implicitParam( "=m0", - + {fbt._( "{user name really long description for prettier} !", [ diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.tsx index c7790be17ecdc..d6aa512b9a53f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.tsx +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-subtree.tsx @@ -10,7 +10,7 @@ import fbt from 'fbt'; function Foo(props) { return ( - + {props.name} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.expect.md index 89aed91eec097..1acfd65d165a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.expect.md @@ -8,13 +8,13 @@ function Foo({name1, name2}) { return ( - + {name1} and - + {name2} @@ -47,14 +47,14 @@ function Foo(t0) { fbt._param( "user1", - + {name1} , ), fbt._param( "user2", - + {name2} , ), diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.tsx index 67cfc3873a8f4..5662455b3ff63 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.tsx +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-preserve-whitespace-two-subtrees.tsx @@ -4,13 +4,13 @@ function Foo({name1, name2}) { return ( - + {name1} and - + {name2} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md index fea502d0d3bfe..afbb1bdfe7843 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/import-as-local.expect.md @@ -137,4 +137,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: exception) (0 , _react.experimental_useEffectEvent) is not a function \ No newline at end of file +(kind: ok)
Hello
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md index 5c870b43aff1c..a47554cfca072 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/module-scoped-bindings.expect.md @@ -101,4 +101,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: ok) [{"Children":{"map":"[[ function params=3 ]]","forEach":"[[ function params=3 ]]","count":"[[ function params=1 ]]","toArray":"[[ function params=1 ]]","only":"[[ function params=1 ]]"},"Component":"[[ function params=3 ]]","PureComponent":"[[ function params=3 ]]","__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE":{"H":{"readContext":"[[ function params=1 ]]","use":"[[ function params=1 ]]","useCallback":"[[ function params=2 ]]","useContext":"[[ function params=1 ]]","useEffect":"[[ function params=2 ]]","useImperativeHandle":"[[ function params=3 ]]","useInsertionEffect":"[[ function params=2 ]]","useLayoutEffect":"[[ function params=2 ]]","useMemo":"[[ function params=2 ]]","useReducer":"[[ function params=3 ]]","useRef":"[[ function params=1 ]]","useState":"[[ function params=1 ]]","useDebugValue":"[[ function params=2 ]]","useDeferredValue":"[[ function params=2 ]]","useTransition":"[[ function params=0 ]]","useSyncExternalStore":"[[ function params=3 ]]","useId":"[[ function params=0 ]]","useCacheRefresh":"[[ function params=0 ]]","useMemoCache":"[[ function params=1 ]]","useHostTransitionStatus":"[[ function params=0 ]]","useFormState":"[[ function params=3 ]]","useActionState":"[[ function params=3 ]]","useOptimistic":"[[ function params=2 ]]"},"A":{"getCacheForType":"[[ function params=1 ]]","getOwner":"[[ function params=0 ]]"},"T":null,"actQueue":["[[ function params=0 ]]","[[ function params=1 ]]"],"isBatchingLegacy":false,"didScheduleLegacyUpdate":false,"didUsePromise":false,"thrownErrors":[],"setExtraStackFrame":"[[ function params=1 ]]","getCurrentStack":"[[ function params=0 ]]","getStackAddendum":"[[ function params=0 ]]"},"act":"[[ function params=1 ]]","cache":"[[ function params=1 ]]","cloneElement":"[[ function params=3 ]]","createContext":"[[ function params=1 ]]","createElement":"[[ function params=3 ]]","createRef":"[[ function params=0 ]]","forwardRef":"[[ function params=1 ]]","isValidElement":"[[ function params=1 ]]","lazy":"[[ function params=1 ]]","memo":"[[ function params=2 ]]","startTransition":"[[ function params=2 ]]","unstable_useCacheRefresh":"[[ function params=0 ]]","use":"[[ function params=1 ]]","useActionState":"[[ function params=3 ]]","useCallback":"[[ function params=2 ]]","useContext":"[[ function params=1 ]]","useDebugValue":"[[ function params=2 ]]","useDeferredValue":"[[ function params=2 ]]","useEffect":"[[ function params=2 ]]","useId":"[[ function params=0 ]]","useImperativeHandle":"[[ function params=3 ]]","useInsertionEffect":"[[ function params=2 ]]","useLayoutEffect":"[[ function params=2 ]]","useMemo":"[[ function params=2 ]]","useOptimistic":"[[ function params=2 ]]","useReducer":"[[ function params=3 ]]","useRef":"[[ function params=1 ]]","useState":"[[ function params=1 ]]","useSyncExternalStore":"[[ function params=3 ]]","useTransition":"[[ function params=0 ]]","version":"19.0.0-beta-b498834eab-20240506"},"[[ cyclic ref *6 ]]",true,true,true,true,"[[ function params=0 ]]",true,"[[ function params=0 ]]"] \ No newline at end of file +(kind: ok) [{"Children":{"map":"[[ function params=3 ]]","forEach":"[[ function params=3 ]]","count":"[[ function params=1 ]]","toArray":"[[ function params=1 ]]","only":"[[ function params=1 ]]"},"Component":"[[ function params=3 ]]","PureComponent":"[[ function params=3 ]]","__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE":{"H":{"readContext":"[[ function params=1 ]]","use":"[[ function params=1 ]]","useCallback":"[[ function params=2 ]]","useContext":"[[ function params=1 ]]","useEffect":"[[ function params=2 ]]","useImperativeHandle":"[[ function params=3 ]]","useInsertionEffect":"[[ function params=2 ]]","useLayoutEffect":"[[ function params=2 ]]","useMemo":"[[ function params=2 ]]","useReducer":"[[ function params=3 ]]","useRef":"[[ function params=1 ]]","useState":"[[ function params=1 ]]","useDebugValue":"[[ function params=0 ]]","useDeferredValue":"[[ function params=2 ]]","useTransition":"[[ function params=0 ]]","useSyncExternalStore":"[[ function params=3 ]]","useId":"[[ function params=0 ]]","useCacheRefresh":"[[ function params=0 ]]","useMemoCache":"[[ function params=1 ]]","useEffectEvent":"[[ function params=1 ]]","useHostTransitionStatus":"[[ function params=0 ]]","useFormState":"[[ function params=2 ]]","useActionState":"[[ function params=2 ]]","useOptimistic":"[[ function params=1 ]]"},"A":{"getCacheForType":"[[ function params=1 ]]","getOwner":"[[ function params=0 ]]"},"T":null,"S":"[[ function params=2 ]]","actQueue":["[[ function params=0 ]]","[[ function params=1 ]]"],"isBatchingLegacy":false,"didScheduleLegacyUpdate":false,"didUsePromise":false,"thrownErrors":[],"getCurrentStack":"[[ function params=0 ]]"},"__COMPILER_RUNTIME":{"c":"[[ function params=1 ]]"},"act":"[[ function params=1 ]]","cache":"[[ function params=1 ]]","captureOwnerStack":"[[ function params=0 ]]","cloneElement":"[[ function params=3 ]]","createContext":"[[ function params=1 ]]","createElement":"[[ function params=3 ]]","createRef":"[[ function params=0 ]]","experimental_useEffectEvent":"[[ function params=1 ]]","experimental_useOptimistic":"[[ function params=2 ]]","forwardRef":"[[ function params=1 ]]","isValidElement":"[[ function params=1 ]]","lazy":"[[ function params=1 ]]","memo":"[[ function params=2 ]]","startTransition":"[[ function params=1 ]]","unstable_getCacheForType":"[[ function params=1 ]]","unstable_postpone":"[[ function params=1 ]]","unstable_useCacheRefresh":"[[ function params=0 ]]","use":"[[ function params=1 ]]","useActionState":"[[ function params=3 ]]","useCallback":"[[ function params=2 ]]","useContext":"[[ function params=1 ]]","useDebugValue":"[[ function params=2 ]]","useDeferredValue":"[[ function params=2 ]]","useEffect":"[[ function params=2 ]]","useId":"[[ function params=0 ]]","useImperativeHandle":"[[ function params=3 ]]","useInsertionEffect":"[[ function params=2 ]]","useLayoutEffect":"[[ function params=2 ]]","useMemo":"[[ function params=2 ]]","useOptimistic":"[[ function params=2 ]]","useReducer":"[[ function params=3 ]]","useRef":"[[ function params=1 ]]","useState":"[[ function params=1 ]]","useSyncExternalStore":"[[ function params=3 ]]","useTransition":"[[ function params=0 ]]","version":"19.0.0-experimental-0bc30748-20241028"},"[[ cyclic ref *6 ]]",true,true,true,true,"[[ function params=0 ]]",true,"[[ function params=0 ]]"] \ No newline at end of file diff --git a/compiler/packages/snap/package.json b/compiler/packages/snap/package.json index 3754260dffeed..f0272af642969 100644 --- a/compiler/packages/snap/package.json +++ b/compiler/packages/snap/package.json @@ -33,8 +33,8 @@ "glob": "^10.3.10", "hermes-parser": "^0.19.1", "jsdom": "^22.1.0", - "react": "19.0.0-beta-b498834eab-20240506", - "react-dom": "19.0.0-beta-b498834eab-20240506", + "react": "0.0.0-experimental-0bc30748-20241028", + "react-dom": "0.0.0-experimental-0bc30748-20241028", "readline": "^1.3.0", "yargs": "^17.7.1" }, diff --git a/compiler/yarn.lock b/compiler/yarn.lock index 8239089c72992..8265c8f48e9ec 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -44,15 +44,24 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" +"@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.0.tgz#9374b5cd068d128dac0b94ff482594273b1c2815" + integrity sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.22.0", "@babel/compat-data@^7.22.3": version "7.22.3" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.3.tgz#cd502a6a0b6e37d7ad72ce7e71a7160a3ae36f7e" integrity sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ== -"@babel/compat-data@^7.25.2": - version "7.25.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb" - integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ== +"@babel/compat-data@^7.25.9": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.0.tgz#f02ba6d34e88fadd5e8861e8b38902f43cc1c819" + integrity sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA== "@babel/core@^7.0.0", "@babel/core@^7.2.0": version "7.2.0" @@ -75,20 +84,20 @@ source-map "^0.5.0" "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.19.1", "@babel/core@^7.24.4": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.2.tgz#ed8eec275118d7613e77a352894cd12ded8eba77" - integrity sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA== + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.0" - "@babel/helper-compilation-targets" "^7.25.2" - "@babel/helper-module-transforms" "^7.25.2" - "@babel/helpers" "^7.25.0" - "@babel/parser" "^7.25.0" - "@babel/template" "^7.25.0" - "@babel/traverse" "^7.25.2" - "@babel/types" "^7.25.2" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -106,15 +115,16 @@ source-map "^0.5.0" trim-right "^1.0.1" -"@babel/generator@^7.25.0", "@babel/generator@^7.25.6", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.6.tgz#0df1ad8cb32fe4d2b01d8bf437f153d19342a87c" - integrity sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw== +"@babel/generator@^7.25.9", "@babel/generator@^7.26.0", "@babel/generator@^7.7.2", "@babel/generator@^7.7.4": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.0.tgz#505cc7c90d92513f458a477e5ef0703e7c91b8d7" + integrity sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w== dependencies: - "@babel/types" "^7.25.6" + "@babel/parser" "^7.26.0" + "@babel/types" "^7.26.0" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" + jsesc "^3.0.2" "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" @@ -148,14 +158,14 @@ lru-cache "^5.1.1" semver "^6.3.0" -"@babel/helper-compilation-targets@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz#e1d9410a90974a3a5a66e84ff55ef62e3c02d06c" - integrity sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw== +"@babel/helper-compilation-targets@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" + integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== dependencies: - "@babel/compat-data" "^7.25.2" - "@babel/helper-validator-option" "^7.24.8" - browserslist "^4.23.1" + "@babel/compat-data" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" lru-cache "^5.1.1" semver "^6.3.1" @@ -312,13 +322,13 @@ dependencies: "@babel/types" "^7.21.4" -"@babel/helper-module-imports@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" "@babel/helper-module-transforms@^7.18.6": version "7.19.0" @@ -362,15 +372,14 @@ "@babel/traverse" "^7.21.2" "@babel/types" "^7.21.2" -"@babel/helper-module-transforms@^7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz#ee713c29768100f2776edf04d4eb23b8d27a66e6" - integrity sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ== +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== dependencies: - "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-simple-access" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" - "@babel/traverse" "^7.25.2" + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" @@ -469,14 +478,6 @@ dependencies: "@babel/types" "^7.21.5" -"@babel/helper-simple-access@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" - integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== - dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" - "@babel/helper-skip-transparent-expression-wrappers@^7.20.0": version "7.20.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" @@ -537,6 +538,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -552,6 +558,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + "@babel/helper-validator-option@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" @@ -567,10 +578,10 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== -"@babel/helper-validator-option@^7.24.8": - version "7.24.8" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" - integrity sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q== +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== "@babel/helper-wrap-function@^7.18.9": version "7.20.5" @@ -591,13 +602,13 @@ "@babel/traverse" "^7.19.0" "@babel/types" "^7.19.0" -"@babel/helpers@^7.25.0": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60" - integrity sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q== +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== dependencies: - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.6" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" "@babel/highlight@^7.18.6": version "7.18.6" @@ -657,13 +668,20 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== -"@babel/parser@^7.25.0", "@babel/parser@^7.25.6": +"@babel/parser@^7.25.0": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f" integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q== dependencies: "@babel/types" "^7.25.6" +"@babel/parser@^7.25.9", "@babel/parser@^7.26.0": + version "7.26.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.1.tgz#44e02499960df2cdce2c456372a3e8e0c3c5c975" + integrity sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw== + dependencies: + "@babel/types" "^7.26.0" + "@babel/parser@^7.7.4": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" @@ -1545,7 +1563,7 @@ "@babel/parser" "^7.22.5" "@babel/types" "^7.22.5" -"@babel/template@^7.24.7", "@babel/template@^7.25.0": +"@babel/template@^7.24.7": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" integrity sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q== @@ -1554,6 +1572,15 @@ "@babel/parser" "^7.25.0" "@babel/types" "^7.25.0" +"@babel/template@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + "@babel/template@^7.3.3": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" @@ -1578,16 +1605,16 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.21.2", "@babel/traverse@^7.22.1", "@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2": - version "7.25.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.6.tgz#04fad980e444f182ecf1520504941940a90fea41" - integrity sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ== +"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.21.2", "@babel/traverse@^7.22.1", "@babel/traverse@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" + integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.25.6" - "@babel/parser" "^7.25.6" - "@babel/template" "^7.25.0" - "@babel/types" "^7.25.6" + "@babel/code-frame" "^7.25.9" + "@babel/generator" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/template" "^7.25.9" + "@babel/types" "^7.25.9" debug "^4.3.1" globals "^11.1.0" @@ -1644,7 +1671,7 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" -"@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6", "@babel/types@^7.7.4": +"@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.6", "@babel/types@^7.7.4": version "7.25.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6" integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw== @@ -1653,6 +1680,14 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@babel/types@^7.25.9", "@babel/types@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff" + integrity sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -3549,15 +3584,15 @@ browserslist@^4.21.3, browserslist@^4.21.5: node-releases "^2.0.12" update-browserslist-db "^1.0.11" -browserslist@^4.23.1: - version "4.24.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" - integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== +browserslist@^4.24.0: + version "4.24.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.2.tgz#f5845bc91069dbd55ee89faf9822e1d885d16580" + integrity sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg== dependencies: - caniuse-lite "^1.0.30001663" - electron-to-chromium "^1.5.28" + caniuse-lite "^1.0.30001669" + electron-to-chromium "^1.5.41" node-releases "^2.0.18" - update-browserslist-db "^1.1.0" + update-browserslist-db "^1.1.1" bs-logger@0.x: version "0.2.6" @@ -3619,10 +3654,10 @@ caniuse-lite@^1.0.30001489: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz" integrity sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ== -caniuse-lite@^1.0.30001663: - version "1.0.30001664" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001664.tgz#d588d75c9682d3301956b05a3749652a80677df4" - integrity sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g== +caniuse-lite@^1.0.30001669: + version "1.0.30001674" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001674.tgz#eb200a716c3e796d33d30b9c8890517a72f862c8" + integrity sha512-jOsKlZVRnzfhLojb+Ykb+gyUSp9Xb57So+fAiFlLzzTKpqg8xxSav0e40c8/4F/v9N8QSvrRRaLeVzQbLqomYw== chalk@4, chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" @@ -4011,10 +4046,10 @@ electron-to-chromium@^1.4.411: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.418.tgz#9092aca12db25acf02a2ddf9de59f0e4363c9928" integrity sha512-1KnpDTS9onwAfMzW50LcpNtyOkMyjd/OLoD2Kx/DDITZqgNYixY71XNszPHNxyQQ/Brh+FDcUnf4BaM041sdWg== -electron-to-chromium@^1.5.28: - version "1.5.29" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.29.tgz#aa592a3caa95d07cc26a66563accf99fa573a1ee" - integrity sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw== +electron-to-chromium@^1.5.41: + version "1.5.49" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.49.tgz#9358f514ab6eeed809a8689f4b39ea5114ae729c" + integrity sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A== emittery@^0.10.2: version "0.10.2" @@ -4058,7 +4093,7 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escalade@^3.1.2: +escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== @@ -6157,6 +6192,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -6722,10 +6762,10 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picocolors@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== +picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -6885,22 +6925,22 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -react-dom@19.0.0-beta-b498834eab-20240506: - version "19.0.0-beta-b498834eab-20240506" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-b498834eab-20240506.tgz#1860706b1b5b68850fad0f44d08ae43311fe1171" - integrity sha512-k+o/NB0245cUhJXQj8S9YWlGc+3aNNRMUwhmSP22UA422jucLYg5N5eHYwNTr7EWNR/xJ1uZXodX+Ur9JvKCuQ== +react-dom@0.0.0-experimental-0bc30748-20241028: + version "0.0.0-experimental-0bc30748-20241028" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.0.0-experimental-0bc30748-20241028.tgz#07061961b4fd80b1e85dbf1005ce5391eedae845" + integrity sha512-0+hMpMC2cJMhsb4umbXGxSfCiPct4HfA8M4vJUyLZ/Z2tV4QsaE7ptVO/WwYYxxTf17dwBqkESMb6RRVCVHNQQ== dependencies: - scheduler "0.25.0-beta-b498834eab-20240506" + scheduler "0.0.0-experimental-0bc30748-20241028" react-is@19.0.0-beta-b498834eab-20240506, react-is@^16.8.4, react-is@^17.0.1, react-is@^18.0.0: version "19.0.0-beta-b498834eab-20240506" resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.0.0-beta-b498834eab-20240506.tgz#772f7d3ff4997997730f54cad28282214b487294" integrity sha512-n4bHxssA5Y0y1Vx4P0aBybxp0VviakagM9wgP961sVCj2hndZqb/NcVEmIkwxAL2ha4kv/l1zaUiIH+4fSZJkg== -react@19.0.0-beta-b498834eab-20240506: - version "19.0.0-beta-b498834eab-20240506" - resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-beta-b498834eab-20240506.tgz#36a99a1160ca055725a092630641c2dd77b62f33" - integrity sha512-mK8kVx7e0M6bVvjc+G+48Oo4TJJ1Y84JUrs60MbIw8WoqqHmG9qPFz3IwhXqzVtugqBMog5UA4KEZW+nHxewkw== +react@0.0.0-experimental-0bc30748-20241028: + version "0.0.0-experimental-0bc30748-20241028" + resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-experimental-0bc30748-20241028.tgz#e9f5c8d32531088e7d9be508c498491da7e1d462" + integrity sha512-7H9ezZboHMmKfTZ/J6fwO3+EzufgJsr1vDpcB+GL9nE8Qg8jRx/tk7GMmS2pdjYgJzgzL3Lhfc6pSkoTshbJhw== readable-stream@^3.4.0: version "3.6.2" @@ -7130,10 +7170,10 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" -scheduler@0.25.0-beta-b498834eab-20240506: - version "0.25.0-beta-b498834eab-20240506" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-b498834eab-20240506.tgz#ddbdfe82bdf7a4dda551974c54b9b68e75cb9ba1" - integrity sha512-fw52C9FJ90xSu8R2vRfYX8WiI3sz4zo/ya98DRdRqkkgek6WYofI7AJRM5ZZxFtVKuJZOUjV+4uoVK9Al1XadA== +scheduler@0.0.0-experimental-0bc30748-20241028: + version "0.0.0-experimental-0bc30748-20241028" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.0.0-experimental-0bc30748-20241028.tgz#6fafb09ff72b4f375bfd1c916d11cde0607d2835" + integrity sha512-gqr4QbUBcIZ7igLan4v4eTYHszX3BkLwbiaiNaQVpbS3IzI/oXZPJAOxqZIctf9JMPa80Bblk4WaXoSR4mHS7Q== semver@7.x, semver@^7.3.5: version "7.3.7" @@ -7615,13 +7655,13 @@ update-browserslist-db@^1.0.11: escalade "^3.1.1" picocolors "^1.0.0" -update-browserslist-db@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz#7ca61c0d8650766090728046e416a8cde682859e" - integrity sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ== +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.2" - picocolors "^1.0.1" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2: version "4.4.1" From ea3ac586693014e882655728fc8396ecb1d6cf6e Mon Sep 17 00:00:00 2001 From: Timothy Yung Date: Thu, 31 Oct 2024 13:24:45 -0700 Subject: [PATCH 328/426] Fix Ref Lifecycles in Hidden Subtrees (#31379) ## Summary We're seeing certain situations in React Native development where ref callbacks in `` are sometimes invoked exactly once with `null` without ever being called with a "current" value. This violates the contract for refs because refs are expected to always attach before detach (and to always eventually detach after attach). This is *particularly* bad for refs that return cleanup functions, because refs that return cleanup functions expect to never be invoked with `null`. This bug causes such refs to be invoked with `null` (because since `safelyAttachRef` was never called, `safelyDetachRef` thinks the ref does not return a cleanup function and invokes it with `null`). This fix makes use of `offscreenSubtreeWasHidden` in `commitDeletionEffectsOnFiber`, similar to how https://github.com/facebook/react/commit/ec52a5698e2dfea7050a0b015f0b79abfb2d81b7 did this for `commitDeletionEffectsOnFiber`. ## How did you test this change? We were able to isolate the repro steps to isolate the React Native experimental changes. However, the repro steps depend on Fast Refresh. ``` function callbackRef(current) { // Called once with `current` as null, upon triggering Fast Refresh. } ; ``` Ideally, we would have a unit test that verifies this behavior without Fast Refresh. (We have evidence that this bug occurs without Fast Refresh in real product implementations. However, we have not successfully deduced the root cause, yet.) This PR currently includes a unit test that reproduces the Fast Refresh scenario, which is also demonstrated in this CodeSandbox: https://codesandbox.io/p/sandbox/hungry-darkness-33wxy7 Verified unit tests pass: ``` $ yarn $ yarn test # Run with `-r=www-classic` for `enableScopeAPI` tests. $ yarn test -r=www-classic ``` Verified on the internal React Native development branch that the bug no longer repros. --------- Co-authored-by: Rick Hanlon --- .../src/ReactFiberCommitWork.js | 24 ++-- .../__tests__/ReactFreshIntegration-test.js | 125 ++++++++++++++++++ 2 files changed, 140 insertions(+), 9 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 89aa35d760b26..9384f5cbd574b 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -1325,7 +1325,9 @@ function commitDeletionEffectsOnFiber( } case ScopeComponent: { if (enableScopeAPI) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } } recursivelyTraverseDeletionEffects( finishedRoot, @@ -1335,7 +1337,9 @@ function commitDeletionEffectsOnFiber( return; } case OffscreenComponent: { - safelyDetachRef(deletedFiber, nearestMountedAncestor); + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } if (disableLegacyMode || deletedFiber.mode & ConcurrentMode) { // If this offscreen component is hidden, we already unmounted it. Before // deleting the children, track that it's already unmounted so that we @@ -1572,7 +1576,7 @@ function recursivelyTraverseMutationEffects( lanes: Lanes, ) { // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects hae fired. + // before the children effects have fired. const deletions = parentFiber.deletions; if (deletions !== null) { for (let i = 0; i < deletions.length; i++) { @@ -1637,7 +1641,7 @@ function commitMutationEffectsOnFiber( commitReconciliationEffects(finishedWork); if (flags & Ref) { - if (current !== null) { + if (!offscreenSubtreeWasHidden && current !== null) { safelyDetachRef(current, current.return); } } @@ -1660,7 +1664,7 @@ function commitMutationEffectsOnFiber( commitReconciliationEffects(finishedWork); if (flags & Ref) { - if (current !== null) { + if (!offscreenSubtreeWasHidden && current !== null) { safelyDetachRef(current, current.return); } } @@ -1745,7 +1749,7 @@ function commitMutationEffectsOnFiber( commitReconciliationEffects(finishedWork); if (flags & Ref) { - if (current !== null) { + if (!offscreenSubtreeWasHidden && current !== null) { safelyDetachRef(current, current.return); } } @@ -1961,7 +1965,7 @@ function commitMutationEffectsOnFiber( } case OffscreenComponent: { if (flags & Ref) { - if (current !== null) { + if (!offscreenSubtreeWasHidden && current !== null) { safelyDetachRef(current, current.return); } } @@ -2074,10 +2078,12 @@ function commitMutationEffectsOnFiber( // TODO: This is a temporary solution that allowed us to transition away // from React Flare on www. if (flags & Ref) { - if (current !== null) { + if (!offscreenSubtreeWasHidden && current !== null) { safelyDetachRef(finishedWork, finishedWork.return); } - safelyAttachRef(finishedWork, finishedWork.return); + if (!offscreenSubtreeIsHidden) { + safelyAttachRef(finishedWork, finishedWork.return); + } } if (flags & Update) { const scopeInstance = finishedWork.stateNode; diff --git a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js index cc9deb6236011..093d164e70964 100644 --- a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js +++ b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js @@ -305,6 +305,131 @@ describe('ReactFreshIntegration', () => { } }); + // @gate __DEV__ && enableActivity + it('ignores ref for class component in hidden subtree', async () => { + const code = ` + import {unstable_Activity as Activity} from 'react'; + + // Avoid creating a new class on Fast Refresh. + global.A = global.A ?? class A extends React.Component { + render() { + return
; + } + } + const A = global.A; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + + + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity + it('ignores ref for hoistable resource in hidden subtree', async () => { + const code = ` + import {unstable_Activity as Activity} from 'react'; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + + + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity + it('ignores ref for host component in hidden subtree', async () => { + const code = ` + import {unstable_Activity as Activity} from 'react'; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + +
+ + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity + it('ignores ref for Activity in hidden subtree', async () => { + const code = ` + import {unstable_Activity as Activity} from 'react'; + + function hiddenRef(value) { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + +
+ + + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity && enableScopeAPI + it('ignores ref for Scope in hidden subtree', async () => { + const code = ` + import { + unstable_Activity as Activity, + unstable_Scope as Scope, + } from 'react'; + + function hiddenRef(value) { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + +
+ + + ); + }; + `; + + await render(code); + await patch(code); + }); + it('reloads HOCs if they return functions', async () => { if (__DEV__) { await render(` From b7e21579220042c0a60179e2f40f121684e637eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 31 Oct 2024 16:47:51 -0400 Subject: [PATCH 329/426] [Flight] Handle errors during JSON stringify of console values (#31391) When we serialize debug info we should never error even though we don't currently support everything being serialized. Since it's non-essential dev information. We already handle errors in the replacer but not when errors happen in the JSON algorithm itself - such as cyclic errors. We should ideally support cyclic objects but regardless we should gracefully handle the errors. --- .../src/__tests__/ReactFlight-test.js | 59 +++++++++++++++++++ .../react-server/src/ReactFlightServer.js | 31 ++++++++-- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 139a75f12982f..47c6db808f043 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -3146,6 +3146,65 @@ describe('ReactFlight', () => { expect(ownerStacks).toEqual(['\n in App (at **)']); }); + // @gate enableServerComponentLogs && __DEV__ + it('replays logs with cyclic objects', async () => { + const cyclic = {cycle: null}; + cyclic.cycle = cyclic; + + function ServerComponent() { + console.log('hi', {cyclic}); + return null; + } + + function App() { + return ReactServer.createElement(ServerComponent); + } + + // These tests are specifically testing console.log. + // Assign to `mockConsoleLog` so we can still inspect it when `console.log` + // is overridden by the test modules. The original function will be restored + // after this test finishes by `jest.restoreAllMocks()`. + const mockConsoleLog = spyOnDevAndProd(console, 'log').mockImplementation( + () => {}, + ); + + // Reset the modules so that we get a new overridden console on top of the + // one installed by expect. This ensures that we still emit console.error + // calls. + jest.resetModules(); + jest.mock('react', () => require('react/react.react-server')); + ReactServer = require('react'); + ReactNoopFlightServer = require('react-noop-renderer/flight-server'); + const transport = ReactNoopFlightServer.render({ + root: ReactServer.createElement(App), + }); + + expect(mockConsoleLog).toHaveBeenCalledTimes(1); + expect(mockConsoleLog.mock.calls[0][0]).toBe('hi'); + expect(mockConsoleLog.mock.calls[0][1].cyclic).toBe(cyclic); + mockConsoleLog.mockClear(); + mockConsoleLog.mockImplementation(() => {}); + + // The error should not actually get logged because we're not awaiting the root + // so it's not thrown but the server log also shouldn't be replayed. + await ReactNoopFlightClient.read(transport); + + expect(mockConsoleLog).toHaveBeenCalledTimes(1); + // TODO: Support cyclic objects in console encoding. + // expect(mockConsoleLog.mock.calls[0][0]).toBe('hi'); + // const cyclic2 = mockConsoleLog.mock.calls[0][1].cyclic; + // expect(cyclic2).not.toBe(cyclic); // Was serialized and therefore cloned + // expect(cyclic2.cycle).toBe(cyclic2); + expect(mockConsoleLog.mock.calls[0][0]).toBe( + 'Unknown Value: React could not send it from the server.', + ); + expect(mockConsoleLog.mock.calls[0][1].message).toBe( + 'Converting circular structure to JSON\n' + + " --> starting at object with constructor 'Object'\n" + + " --- property 'cycle' closes the circle", + ); + }); + it('uses the server component debug info as the element owner in DEV', async () => { function Container({children}) { return children; diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index ca238271e20d6..75d5947baecef 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -3750,8 +3750,16 @@ function outlineConsoleValue( } } - // $FlowFixMe[incompatible-type] stringify can return null - const json: string = stringify(model, replacer); + let json: string; + try { + // $FlowFixMe[incompatible-cast] stringify can return null + json = (stringify(model, replacer): string); + } catch (x) { + // $FlowFixMe[incompatible-cast] stringify can return null + json = (stringify( + 'Unknown Value: React could not send it from the server.\n' + x.message, + ): string); + } request.pendingChunks++; const id = request.nextChunkId++; @@ -3810,8 +3818,23 @@ function emitConsoleChunk( const payload = [methodName, stackTrace, owner, env]; // $FlowFixMe[method-unbinding] payload.push.apply(payload, args); - // $FlowFixMe[incompatible-type] stringify can return null - const json: string = stringify(payload, replacer); + let json: string; + try { + // $FlowFixMe[incompatible-type] stringify can return null + json = stringify(payload, replacer); + } catch (x) { + json = stringify( + [ + methodName, + stackTrace, + owner, + env, + 'Unknown Value: React could not send it from the server.', + x, + ], + replacer, + ); + } const row = serializeRowHeader('W', id) + json + '\n'; const processedChunk = stringToChunk(row); request.completedRegularChunks.push(processedChunk); From 16409d0560863dac41880bd308dea6efee46087a Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 1 Nov 2024 15:16:26 -0700 Subject: [PATCH 330/426] temporarily disable lazy context propagation (#31403) disables lazy context propagation in oss to help determine if it is causing bugs in startTransition. Will reenable after cutting a canary release with this flag disabled --- packages/shared/ReactFeatureFlags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 5a11217452e57..37f3b036392c2 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -101,7 +101,7 @@ export const enableObjectFiber = false; export const enableTransitionTracing = false; -export const enableLazyContextPropagation = true; +export const enableLazyContextPropagation = false; // Expose unstable useContext for performance testing export const enableContextProfiling = false; From 7c8e5e7ab8bb63de911637892392c5efd8ce1d0f Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 1 Nov 2024 15:17:51 -0700 Subject: [PATCH 331/426] Reenable lazy context propagation (#31405) Reverts facebook/react#31403 to reenable lazy context propagation The disabling was to produce a build that could help track down whether this flag is causing a possibly related bug in transitions but we don't intend to disable it just fix forward once we figure out what the problem is --- packages/shared/ReactFeatureFlags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 37f3b036392c2..5a11217452e57 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -101,7 +101,7 @@ export const enableObjectFiber = false; export const enableTransitionTracing = false; -export const enableLazyContextPropagation = false; +export const enableLazyContextPropagation = true; // Expose unstable useContext for performance testing export const enableContextProfiling = false; From 4d577fd216735384a262cbacdcbc5cda18626497 Mon Sep 17 00:00:00 2001 From: Timothy Yung Date: Mon, 4 Nov 2024 07:46:28 -0800 Subject: [PATCH 332/426] More Unit Tests for Refs in Hidden Subtrees (#31404) ## Summary While fixing ref lifecycles in hidden subtrees in https://github.com/facebook/react/pull/31379, @rickhanlonii noticed that we could also add more unit tests for other types of tags to prevent future regressions during code refactors. This PR adds more unit tests in the same vein as those added in https://github.com/facebook/react/pull/31379. ## How did you test this change? Verified unit tests pass: ``` $ yarn $ yarn test ReactFreshIntegration-test.js ``` --- .../__tests__/ReactFreshIntegration-test.js | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js index 093d164e70964..d851d72eb4c29 100644 --- a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js +++ b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js @@ -430,6 +430,131 @@ describe('ReactFreshIntegration', () => { await patch(code); }); + // @gate __DEV__ && enableActivity + it('ignores ref for functional component in hidden subtree', async () => { + const code = ` + import {unstable_Activity as Activity} from 'react'; + + // Avoid creating a new component on Fast Refresh. + global.A = global.A ?? function A() { + return
; + } + const A = global.A; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + + + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity + it('ignores ref for ref forwarding component in hidden subtree', async () => { + const code = ` + import { + forwardRef, + unstable_Activity as Activity, + } from 'react'; + + // Avoid creating a new component on Fast Refresh. + global.A = global.A ?? forwardRef(function A(props, ref) { + return
; + }); + const A = global.A; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + + + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity + it('ignores ref for simple memo component in hidden subtree', async () => { + const code = ` + import { + memo, + unstable_Activity as Activity, + } from 'react'; + + // Avoid creating a new component on Fast Refresh. + global.A = global.A ?? memo(function A() { + return
; + }); + const A = global.A; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + + + ); + }; + `; + + await render(code); + await patch(code); + }); + + // @gate __DEV__ && enableActivity + it('ignores ref for memo component in hidden subtree', async () => { + // A custom compare function means this won't use SimpleMemoComponent. + const code = ` + import { + memo, + unstable_Activity as Activity, + } from 'react'; + + // Avoid creating a new component on Fast Refresh. + global.A = global.A ?? memo( + function A() { + return
; + }, + () => false, + ); + const A = global.A; + + function hiddenRef() { + throw new Error('Unexpected hiddenRef() invocation.'); + } + + export default function App() { + return ( + + + + ); + }; + `; + + await render(code); + await patch(code); + }); + it('reloads HOCs if they return functions', async () => { if (__DEV__) { await render(` From 543eb0932155fcf8481c457ed98200006ad57cf5 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 4 Nov 2024 13:19:05 -0500 Subject: [PATCH 333/426] [compiler] Wrap inline jsx transform codegen in conditional (#31267) JSX inlining is a prod-only optimization. We want to enforce this while maintaining the same compiler output in DEV and PROD. Here we add a conditional to the transform that only replaces JSX with object literals outside of DEV. Then a later build step can handle DCE based on the value of `__DEV__` --- .../src/HIR/Environment.ts | 1 + .../src/HIR/HIR.ts | 11 + .../src/Optimization/InlineJsxTransform.ts | 515 ++++++++++++++---- .../compiler/inline-jsx-transform.expect.md | 375 +++++++++---- .../fixtures/compiler/inline-jsx-transform.js | 16 + compiler/packages/snap/src/compiler.ts | 5 +- 6 files changed, 694 insertions(+), 229 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index c2918121d2afd..3e2b5597ac446 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -55,6 +55,7 @@ export const ReactElementSymbolSchema = z.object({ z.literal('react.element'), z.literal('react.transitional.element'), ]), + globalDevVar: z.string(), }); export const ExternalFunctionSchema = z.object({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts index 263ec4c20877d..954fb6f40053a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/HIR.ts @@ -1243,6 +1243,17 @@ export function makeTemporaryIdentifier( }; } +export function forkTemporaryIdentifier( + id: IdentifierId, + source: Identifier, +): Identifier { + return { + ...source, + mutableRange: {start: makeInstructionId(0), end: makeInstructionId(0)}, + id, + }; +} + /** * Creates a valid identifier name. This should *not* be used for synthesizing * identifier names: only call this method for identifier names that appear in the diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 89efa78469786..50822e78d977b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -6,14 +6,25 @@ */ import { + BasicBlock, + BlockId, BuiltinTag, + DeclarationId, Effect, + forkTemporaryIdentifier, + GotoTerminal, + GotoVariant, HIRFunction, + Identifier, + IfTerminal, Instruction, + InstructionKind, JsxAttribute, makeInstructionId, ObjectProperty, + Phi, Place, + promoteTemporary, SpreadPattern, } from '../HIR'; import { @@ -24,6 +35,365 @@ import { reversePostorderBlocks, } from '../HIR/HIRBuilder'; import {CompilerError, EnvironmentConfig} from '..'; +import { + mapInstructionLValues, + mapInstructionOperands, + mapInstructionValueOperands, + mapTerminalOperands, +} from '../HIR/visitors'; + +type InlinedJsxDeclarationMap = Map< + DeclarationId, + {identifier: Identifier; blockIdsToIgnore: Set} +>; + +/** + * A prod-only, RN optimization to replace JSX with inlined ReactElement object literals + * + * Example: + * <>foo + * _______________ + * let t1; + * if (__DEV__) { + * t1 = <>foo + * } else { + * t1 = {...} + * } + * + */ +export function inlineJsxTransform( + fn: HIRFunction, + inlineJsxTransformConfig: NonNullable< + EnvironmentConfig['inlineJsxTransform'] + >, +): void { + const inlinedJsxDeclarations: InlinedJsxDeclarationMap = new Map(); + /** + * Step 1: Codegen the conditional and ReactElement object literal + */ + for (const [_, currentBlock] of [...fn.body.blocks]) { + let fallthroughBlockInstructions: Array | null = null; + const instructionCount = currentBlock.instructions.length; + for (let i = 0; i < instructionCount; i++) { + const instr = currentBlock.instructions[i]!; + // TODO: Support value blocks + if (currentBlock.kind === 'value') { + fn.env.logger?.logEvent(fn.env.filename, { + kind: 'CompileDiagnostic', + fnLoc: null, + detail: { + reason: 'JSX Inlining is not supported on value blocks', + loc: instr.loc, + }, + }); + continue; + } + switch (instr.value.kind) { + case 'JsxExpression': + case 'JsxFragment': { + /** + * Split into blocks for new IfTerminal: + * current, then, else, fallthrough + */ + const currentBlockInstructions = currentBlock.instructions.slice( + 0, + i, + ); + const thenBlockInstructions = currentBlock.instructions.slice( + i, + i + 1, + ); + const elseBlockInstructions: Array = []; + fallthroughBlockInstructions ??= currentBlock.instructions.slice( + i + 1, + ); + + const fallthroughBlockId = fn.env.nextBlockId; + const fallthroughBlock: BasicBlock = { + kind: currentBlock.kind, + id: fallthroughBlockId, + instructions: fallthroughBlockInstructions, + terminal: currentBlock.terminal, + preds: new Set(), + phis: new Set(), + }; + + /** + * Complete current block + * - Add instruction for variable declaration + * - Add instruction for LoadGlobal used by conditional + * - End block with a new IfTerminal + */ + const varPlace = createTemporaryPlace(fn.env, instr.value.loc); + promoteTemporary(varPlace.identifier); + const varLValuePlace = createTemporaryPlace(fn.env, instr.value.loc); + const thenVarPlace = { + ...varPlace, + identifier: forkTemporaryIdentifier( + fn.env.nextIdentifierId, + varPlace.identifier, + ), + }; + const elseVarPlace = { + ...varPlace, + identifier: forkTemporaryIdentifier( + fn.env.nextIdentifierId, + varPlace.identifier, + ), + }; + const varInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...varLValuePlace}, + value: { + kind: 'DeclareLocal', + lvalue: {place: {...varPlace}, kind: InstructionKind.Let}, + type: null, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + currentBlockInstructions.push(varInstruction); + + const devGlobalPlace = createTemporaryPlace(fn.env, instr.value.loc); + const devGlobalInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...devGlobalPlace, effect: Effect.Mutate}, + value: { + kind: 'LoadGlobal', + binding: { + kind: 'Global', + name: inlineJsxTransformConfig.globalDevVar, + }, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + currentBlockInstructions.push(devGlobalInstruction); + const thenBlockId = fn.env.nextBlockId; + const elseBlockId = fn.env.nextBlockId; + const ifTerminal: IfTerminal = { + kind: 'if', + test: {...devGlobalPlace, effect: Effect.Read}, + consequent: thenBlockId, + alternate: elseBlockId, + fallthrough: fallthroughBlockId, + loc: instr.loc, + id: makeInstructionId(0), + }; + currentBlock.instructions = currentBlockInstructions; + currentBlock.terminal = ifTerminal; + + /** + * Set up then block where we put the original JSX return + */ + const thenBlock: BasicBlock = { + id: thenBlockId, + instructions: thenBlockInstructions, + kind: 'block', + phis: new Set(), + preds: new Set(), + terminal: { + kind: 'goto', + block: fallthroughBlockId, + variant: GotoVariant.Break, + id: makeInstructionId(0), + loc: instr.loc, + }, + }; + fn.body.blocks.set(thenBlockId, thenBlock); + + const resassignElsePlace = createTemporaryPlace( + fn.env, + instr.value.loc, + ); + const reassignElseInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...resassignElsePlace}, + value: { + kind: 'StoreLocal', + lvalue: { + place: elseVarPlace, + kind: InstructionKind.Reassign, + }, + value: {...instr.lvalue}, + type: null, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + thenBlockInstructions.push(reassignElseInstruction); + + /** + * Set up else block where we add new codegen + */ + const elseBlockTerminal: GotoTerminal = { + kind: 'goto', + block: fallthroughBlockId, + variant: GotoVariant.Break, + id: makeInstructionId(0), + loc: instr.loc, + }; + const elseBlock: BasicBlock = { + id: elseBlockId, + instructions: elseBlockInstructions, + kind: 'block', + phis: new Set(), + preds: new Set(), + terminal: elseBlockTerminal, + }; + fn.body.blocks.set(elseBlockId, elseBlock); + + /** + * ReactElement object literal codegen + */ + const {refProperty, keyProperty, propsProperty} = + createPropsProperties( + fn, + instr, + elseBlockInstructions, + instr.value.kind === 'JsxExpression' ? instr.value.props : [], + instr.value.children, + ); + const reactElementInstructionPlace = createTemporaryPlace( + fn.env, + instr.value.loc, + ); + const reactElementInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...reactElementInstructionPlace, effect: Effect.Store}, + value: { + kind: 'ObjectExpression', + properties: [ + createSymbolProperty( + fn, + instr, + elseBlockInstructions, + '$$typeof', + inlineJsxTransformConfig.elementSymbol, + ), + instr.value.kind === 'JsxExpression' + ? createTagProperty( + fn, + instr, + elseBlockInstructions, + instr.value.tag, + ) + : createSymbolProperty( + fn, + instr, + elseBlockInstructions, + 'type', + 'react.fragment', + ), + refProperty, + keyProperty, + propsProperty, + ], + loc: instr.value.loc, + }, + loc: instr.loc, + }; + elseBlockInstructions.push(reactElementInstruction); + + const reassignConditionalInstruction: Instruction = { + id: makeInstructionId(0), + lvalue: {...createTemporaryPlace(fn.env, instr.value.loc)}, + value: { + kind: 'StoreLocal', + lvalue: { + place: {...elseVarPlace}, + kind: InstructionKind.Reassign, + }, + value: {...reactElementInstruction.lvalue}, + type: null, + loc: instr.value.loc, + }, + loc: instr.loc, + }; + elseBlockInstructions.push(reassignConditionalInstruction); + + /** + * Create phis to reassign the var + */ + const operands: Map = new Map(); + operands.set(thenBlockId, { + ...elseVarPlace, + }); + operands.set(elseBlockId, { + ...thenVarPlace, + }); + + const phiIdentifier = forkTemporaryIdentifier( + fn.env.nextIdentifierId, + varPlace.identifier, + ); + const phiPlace = { + ...createTemporaryPlace(fn.env, instr.value.loc), + identifier: phiIdentifier, + }; + const phis: Set = new Set([ + { + kind: 'Phi', + operands, + place: phiPlace, + }, + ]); + fallthroughBlock.phis = phis; + fn.body.blocks.set(fallthroughBlockId, fallthroughBlock); + + /** + * Track this JSX instruction so we can replace references in step 2 + */ + inlinedJsxDeclarations.set(instr.lvalue.identifier.declarationId, { + identifier: phiIdentifier, + blockIdsToIgnore: new Set([thenBlockId, elseBlockId]), + }); + break; + } + case 'FunctionExpression': + case 'ObjectMethod': { + inlineJsxTransform( + instr.value.loweredFunc.func, + inlineJsxTransformConfig, + ); + break; + } + } + } + } + + /** + * Step 2: Replace declarations with new phi values + */ + for (const [blockId, block] of fn.body.blocks) { + for (const instr of block.instructions) { + mapInstructionOperands(instr, place => + handlePlace(place, blockId, inlinedJsxDeclarations), + ); + + mapInstructionLValues(instr, lvalue => + handlelValue(lvalue, blockId, inlinedJsxDeclarations), + ); + + mapInstructionValueOperands(instr.value, place => + handlePlace(place, blockId, inlinedJsxDeclarations), + ); + } + + mapTerminalOperands(block.terminal, place => + handlePlace(place, blockId, inlinedJsxDeclarations), + ); + } + + /** + * Step 3: Fixup the HIR + * Restore RPO, ensure correct predecessors, renumber instructions, fix scope and ranges. + */ + reversePostorderBlocks(fn.body); + markPredecessors(fn.body); + markInstructionIds(fn.body); + fixScopeAndIdentifierRanges(fn.body); +} function createSymbolProperty( fn: HIRFunction, @@ -315,123 +685,38 @@ function createPropsProperties( return {refProperty, keyProperty, propsProperty}; } -// TODO: Make PROD only with conditional statements -export function inlineJsxTransform( - fn: HIRFunction, - inlineJsxTransformConfig: NonNullable< - EnvironmentConfig['inlineJsxTransform'] - >, -): void { - for (const [, block] of fn.body.blocks) { - let nextInstructions: Array | null = null; - for (let i = 0; i < block.instructions.length; i++) { - const instr = block.instructions[i]!; - switch (instr.value.kind) { - case 'JsxExpression': { - nextInstructions ??= block.instructions.slice(0, i); +function handlePlace( + place: Place, + blockId: BlockId, + inlinedJsxDeclarations: InlinedJsxDeclarationMap, +): Place { + const inlinedJsxDeclaration = inlinedJsxDeclarations.get( + place.identifier.declarationId, + ); + if ( + inlinedJsxDeclaration == null || + inlinedJsxDeclaration.blockIdsToIgnore.has(blockId) + ) { + return {...place}; + } - const {refProperty, keyProperty, propsProperty} = - createPropsProperties( - fn, - instr, - nextInstructions, - instr.value.props, - instr.value.children, - ); - const reactElementInstruction: Instruction = { - id: makeInstructionId(0), - lvalue: {...instr.lvalue, effect: Effect.Store}, - value: { - kind: 'ObjectExpression', - properties: [ - createSymbolProperty( - fn, - instr, - nextInstructions, - '$$typeof', - inlineJsxTransformConfig.elementSymbol, - ), - createTagProperty(fn, instr, nextInstructions, instr.value.tag), - refProperty, - keyProperty, - propsProperty, - ], - loc: instr.value.loc, - }, - loc: instr.loc, - }; - nextInstructions.push(reactElementInstruction); + return {...place, identifier: {...inlinedJsxDeclaration.identifier}}; +} - break; - } - case 'JsxFragment': { - nextInstructions ??= block.instructions.slice(0, i); - const {refProperty, keyProperty, propsProperty} = - createPropsProperties( - fn, - instr, - nextInstructions, - [], - instr.value.children, - ); - const reactElementInstruction: Instruction = { - id: makeInstructionId(0), - lvalue: {...instr.lvalue, effect: Effect.Store}, - value: { - kind: 'ObjectExpression', - properties: [ - createSymbolProperty( - fn, - instr, - nextInstructions, - '$$typeof', - inlineJsxTransformConfig.elementSymbol, - ), - createSymbolProperty( - fn, - instr, - nextInstructions, - 'type', - 'react.fragment', - ), - refProperty, - keyProperty, - propsProperty, - ], - loc: instr.value.loc, - }, - loc: instr.loc, - }; - nextInstructions.push(reactElementInstruction); - break; - } - case 'FunctionExpression': - case 'ObjectMethod': { - inlineJsxTransform( - instr.value.loweredFunc.func, - inlineJsxTransformConfig, - ); - if (nextInstructions !== null) { - nextInstructions.push(instr); - } - break; - } - default: { - if (nextInstructions !== null) { - nextInstructions.push(instr); - } - } - } - } - if (nextInstructions !== null) { - block.instructions = nextInstructions; - } +function handlelValue( + lvalue: Place, + blockId: BlockId, + inlinedJsxDeclarations: InlinedJsxDeclarationMap, +): Place { + const inlinedJsxDeclaration = inlinedJsxDeclarations.get( + lvalue.identifier.declarationId, + ); + if ( + inlinedJsxDeclaration == null || + inlinedJsxDeclaration.blockIdsToIgnore.has(blockId) + ) { + return {...lvalue}; } - // Fixup the HIR to restore RPO, ensure correct predecessors, and renumber instructions. - reversePostorderBlocks(fn.body); - markPredecessors(fn.body); - markInstructionIds(fn.body); - // The renumbering instructions invalidates scope and identifier ranges - fixScopeAndIdentifierRanges(fn.body); + return {...lvalue, identifier: {...inlinedJsxDeclaration.identifier}}; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md index 2078575e83e8a..e657e36d36ee9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -50,6 +50,22 @@ function PropsSpread() { ); } +function ConditionalJsx({shouldWrap}) { + let content =
Hello
; + + if (shouldWrap) { + content = {content}; + } + + return content; +} + +// TODO: Support value blocks +function TernaryJsx({cond}) { + return cond ?
: null; +} + +global.DEV = true; export const FIXTURE_ENTRYPOINT = { fn: ParentAndChildren, params: [{foo: 'abc'}], @@ -67,13 +83,17 @@ function Parent(t0) { const { children, ref } = t0; let t1; if ($[0] !== children) { - t1 = { - $$typeof: Symbol.for("react.transitional.element"), - type: "div", - ref: ref, - key: null, - props: { children: children }, - }; + if (DEV) { + t1 =
{children}
; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: "div", + ref: ref, + key: null, + props: { children: children }, + }; + } $[0] = children; $[1] = t1; } else { @@ -87,13 +107,17 @@ function Child(t0) { const { children } = t0; let t1; if ($[0] !== children) { - t1 = { - $$typeof: Symbol.for("react.transitional.element"), - type: Symbol.for("react.fragment"), - ref: null, - key: null, - props: { children: children }, - }; + if (DEV) { + t1 = <>{children}; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Symbol.for("react.fragment"), + ref: null, + key: null, + props: { children: children }, + }; + } $[0] = children; $[1] = t1; } else { @@ -107,26 +131,34 @@ function GrandChild(t0) { const { className } = t0; let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t1 = { - $$typeof: Symbol.for("react.transitional.element"), - type: React.Fragment, - ref: null, - key: "fragmentKey", - props: { children: "Hello world" }, - }; + if (DEV) { + t1 = Hello world; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: React.Fragment, + ref: null, + key: "fragmentKey", + props: { children: "Hello world" }, + }; + } $[0] = t1; } else { t1 = $[0]; } let t2; if ($[1] !== className) { - t2 = { - $$typeof: Symbol.for("react.transitional.element"), - type: "span", - ref: null, - key: null, - props: { className: className, children: t1 }, - }; + if (DEV) { + t2 = {t1}; + } else { + t2 = { + $$typeof: Symbol.for("react.transitional.element"), + type: "span", + ref: null, + key: null, + props: { className: className, children: t1 }, + }; + } $[1] = className; $[2] = t2; } else { @@ -140,13 +172,17 @@ function ParentAndRefAndKey(props) { const testRef = useRef(); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = { - $$typeof: Symbol.for("react.transitional.element"), - type: Parent, - ref: testRef, - key: "testKey", - props: { a: "a", b: { b: "b" }, c: C }, - }; + if (DEV) { + t0 = ; + } else { + t0 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Parent, + ref: testRef, + key: "testKey", + props: { a: "a", b: { b: "b" }, c: C }, + }; + } $[0] = t0; } else { t0 = $[0]; @@ -158,13 +194,21 @@ function ParentAndChildren(props) { const $ = _c2(14); let t0; if ($[0] !== props.foo) { - t0 = () => ({ - $$typeof: Symbol.for("react.transitional.element"), - type: "div", - ref: null, - key: "d", - props: { children: props.foo }, - }); + t0 = () => { + let t1; + if (DEV) { + t1 =
{props.foo}
; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: "div", + ref: null, + key: "d", + props: { children: props.foo }, + }; + } + return t1; + }; $[0] = props.foo; $[1] = t0; } else { @@ -173,71 +217,99 @@ function ParentAndChildren(props) { const render = t0; let t1; if ($[2] !== props) { - t1 = { - $$typeof: Symbol.for("react.transitional.element"), - type: Child, - ref: null, - key: "a", - props: props, - }; + if (DEV) { + t1 = ; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Child, + ref: null, + key: "a", + props: props, + }; + } $[2] = props; $[3] = t1; } else { t1 = $[3]; } - let t2; + + const t2 = props.foo; + let t3; if ($[4] !== props) { - t2 = { - $$typeof: Symbol.for("react.transitional.element"), - type: GrandChild, - ref: null, - key: "c", - props: { className: props.foo, ...props }, - }; + if (DEV) { + t3 = ; + } else { + t3 = { + $$typeof: Symbol.for("react.transitional.element"), + type: GrandChild, + ref: null, + key: "c", + props: { className: t2, ...props }, + }; + } $[4] = props; - $[5] = t2; + $[5] = t3; } else { - t2 = $[5]; + t3 = $[5]; } - let t3; + let t4; if ($[6] !== render) { - t3 = render(); + t4 = render(); $[6] = render; - $[7] = t3; + $[7] = t4; } else { - t3 = $[7]; + t4 = $[7]; } - let t4; - if ($[8] !== t2 || $[9] !== t3) { - t4 = { - $$typeof: Symbol.for("react.transitional.element"), - type: Child, - ref: null, - key: "b", - props: { children: [t2, t3] }, - }; - $[8] = t2; - $[9] = t3; - $[10] = t4; + let t5; + if ($[8] !== t3 || $[9] !== t4) { + if (DEV) { + t5 = ( + + {t3} + {t4} + + ); + } else { + t5 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Child, + ref: null, + key: "b", + props: { children: [t3, t4] }, + }; + } + $[8] = t3; + $[9] = t4; + $[10] = t5; } else { - t4 = $[10]; + t5 = $[10]; } - let t5; - if ($[11] !== t1 || $[12] !== t4) { - t5 = { - $$typeof: Symbol.for("react.transitional.element"), - type: Parent, - ref: null, - key: null, - props: { children: [t1, t4] }, - }; + let t6; + if ($[11] !== t1 || $[12] !== t5) { + if (DEV) { + t6 = ( + + {t1} + {t5} + + ); + } else { + t6 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Parent, + ref: null, + key: null, + props: { children: [t1, t5] }, + }; + } $[11] = t1; - $[12] = t4; - $[13] = t5; + $[12] = t5; + $[13] = t6; } else { - t5 = $[13]; + t6 = $[13]; } - return t5; + return t6; } const propsToSpread = { a: "a", b: "b", c: "c" }; @@ -245,30 +317,46 @@ function PropsSpread() { const $ = _c2(1); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - t0 = { - $$typeof: Symbol.for("react.transitional.element"), - type: Symbol.for("react.fragment"), - ref: null, - key: null, - props: { - children: [ - { - $$typeof: Symbol.for("react.transitional.element"), - type: Test, - ref: null, - key: "a", - props: propsToSpread, - }, - { - $$typeof: Symbol.for("react.transitional.element"), - type: Test, - ref: null, - key: "b", - props: { ...propsToSpread, a: "z" }, - }, - ], - }, - }; + let t1; + if (DEV) { + t1 = ; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Test, + ref: null, + key: "a", + props: propsToSpread, + }; + } + let t2; + if (DEV) { + t2 = ; + } else { + t2 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Test, + ref: null, + key: "b", + props: { ...propsToSpread, a: "z" }, + }; + } + if (DEV) { + t0 = ( + <> + {t1} + {t2} + + ); + } else { + t0 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Symbol.for("react.fragment"), + ref: null, + key: null, + props: { children: [t1, t2] }, + }; + } $[0] = t0; } else { t0 = $[0]; @@ -276,6 +364,67 @@ function PropsSpread() { return t0; } +function ConditionalJsx(t0) { + const $ = _c2(2); + const { shouldWrap } = t0; + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + if (DEV) { + t1 =
Hello
; + } else { + t1 = { + $$typeof: Symbol.for("react.transitional.element"), + type: "div", + ref: null, + key: null, + props: { children: "Hello" }, + }; + } + $[0] = t1; + } else { + t1 = $[0]; + } + let content = t1; + if (shouldWrap) { + const t2 = content; + let t3; + if ($[1] === Symbol.for("react.memo_cache_sentinel")) { + if (DEV) { + t3 = {t2}; + } else { + t3 = { + $$typeof: Symbol.for("react.transitional.element"), + type: Parent, + ref: null, + key: null, + props: { children: t2 }, + }; + } + $[1] = t3; + } else { + t3 = $[1]; + } + content = t3; + } + return content; +} + +// TODO: Support value blocks +function TernaryJsx(t0) { + const $ = _c2(2); + const { cond } = t0; + let t1; + if ($[0] !== cond) { + t1 = cond ?
: null; + $[0] = cond; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +global.DEV = true; export const FIXTURE_ENTRYPOINT = { fn: ParentAndChildren, params: [{ foo: "abc" }], diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js index 6fe9553dcd5a1..bebb7ad53b80f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js @@ -46,6 +46,22 @@ function PropsSpread() { ); } +function ConditionalJsx({shouldWrap}) { + let content =
Hello
; + + if (shouldWrap) { + content = {content}; + } + + return content; +} + +// TODO: Support value blocks +function TernaryJsx({cond}) { + return cond ?
: null; +} + +global.DEV = true; export const FIXTURE_ENTRYPOINT = { fn: ParentAndChildren, params: [{foo: 'abc'}], diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index cd907575fb797..f0ee88f06e037 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -207,7 +207,10 @@ function makePluginOptions( let inlineJsxTransform: EnvironmentConfig['inlineJsxTransform'] = null; if (firstLine.includes('@enableInlineJsxTransform')) { - inlineJsxTransform = {elementSymbol: 'react.transitional.element'}; + inlineJsxTransform = { + elementSymbol: 'react.transitional.element', + globalDevVar: 'DEV', + }; } let logs: Array<{filename: string | null; event: LoggerEvent}> = []; From 07aa494432e97f63fca9faf2fad6f76fead31063 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Mon, 4 Nov 2024 14:30:58 -0500 Subject: [PATCH 334/426] Remove enableRefAsProp feature flag (#30346) The flag is fully rolled out. --- packages/jest-react/src/JestReact.js | 4 +- .../react-client/src/ReactFlightClient.js | 3 +- .../__tests__/legacy/storeLegacy-v15-test.js | 83 ------- .../__tests__/ReactFunctionComponent-test.js | 217 ------------------ packages/react-dom/src/__tests__/refs-test.js | 18 -- .../src/createReactNoop.js | 8 +- .../react-reconciler/src/ReactChildFiber.js | 53 +---- .../src/ReactFiberBeginWork.js | 29 +-- .../src/ReactFiberClassComponent.js | 15 +- .../src/__tests__/ReactFiberRefs-test.js | 3 +- .../ReactIncrementalSideEffects-test.js | 15 +- .../src/__tests__/ReactLazy-test.internal.js | 24 -- .../src/__tests__/ReactMemo-test.js | 37 --- packages/react-server/src/ReactFizzServer.js | 31 +-- .../react-server/src/ReactFlightServer.js | 15 +- .../ReactTestRenderer-test.internal.js | 41 +--- .../src/__tests__/ReactCreateElement-test.js | 81 +------ .../src/__tests__/ReactElementClone-test.js | 42 +--- .../ReactJSXElementValidator-test.js | 24 +- .../src/__tests__/ReactJSXRuntime-test.js | 29 --- .../ReactJSXTransformIntegration-test.js | 45 +--- packages/react/src/jsx/ReactJSXElement.js | 141 +++--------- packages/shared/ReactFeatureFlags.js | 7 +- .../forks/ReactFeatureFlags.native-fb.js | 1 - .../forks/ReactFeatureFlags.native-oss.js | 1 - .../forks/ReactFeatureFlags.test-renderer.js | 1 - ...actFeatureFlags.test-renderer.native-fb.js | 1 - .../ReactFeatureFlags.test-renderer.www.js | 1 - .../shared/forks/ReactFeatureFlags.www.js | 2 - 29 files changed, 113 insertions(+), 859 deletions(-) diff --git a/packages/jest-react/src/JestReact.js b/packages/jest-react/src/JestReact.js index 4eefc58c85228..8fcec97f63f7a 100644 --- a/packages/jest-react/src/JestReact.js +++ b/packages/jest-react/src/JestReact.js @@ -6,7 +6,7 @@ */ import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols'; -import {disableStringRefs, enableRefAsProp} from 'shared/ReactFeatureFlags'; +import {disableStringRefs} from 'shared/ReactFeatureFlags'; const {assertConsoleLogsCleared} = require('internal-test-utils/consoleMock'); import isArray from 'shared/isArray'; @@ -42,7 +42,7 @@ function assertYieldsWereCleared(root) { } function createJSXElementForTestComparison(type, props) { - if (__DEV__ && enableRefAsProp) { + if (__DEV__) { const element = { $$typeof: REACT_ELEMENT_TYPE, type: type, diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 0e8fad24823e2..6c370bd2ef652 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -44,7 +44,6 @@ import { disableStringRefs, enableBinaryFlight, enablePostpone, - enableRefAsProp, enableFlightReadableStream, enableOwnerStacks, enableServerComponentLogs, @@ -676,7 +675,7 @@ function createElement( | React$Element | LazyComponent, SomeChunk>> { let element: any; - if (__DEV__ && enableRefAsProp) { + if (__DEV__) { // `ref` is non-enumerable in dev element = ({ $$typeof: REACT_ELEMENT_TYPE, diff --git a/packages/react-devtools-shared/src/__tests__/legacy/storeLegacy-v15-test.js b/packages/react-devtools-shared/src/__tests__/legacy/storeLegacy-v15-test.js index 27c841c2b75d0..e4ef6612ecbd8 100644 --- a/packages/react-devtools-shared/src/__tests__/legacy/storeLegacy-v15-test.js +++ b/packages/react-devtools-shared/src/__tests__/legacy/storeLegacy-v15-test.js @@ -868,89 +868,6 @@ describe('Store (legacy)', () => { `); }); - // TODO: These tests don't work when enableRefAsProp is on because the - // JSX runtime that's injected into the test environment by the compiler - // is not compatible with older versions of React. Need to configure the - // the test environment in such a way that certain test modules like this - // one can use an older transform. - if (!require('shared/ReactFeatureFlags').enableRefAsProp) { - it('should support expanding deep parts of the tree', () => { - const Wrapper = ({forwardedRef}) => - React.createElement(Nested, { - depth: 3, - forwardedRef: forwardedRef, - }); - const Nested = ({depth, forwardedRef}) => - depth > 0 - ? React.createElement(Nested, { - depth: depth - 1, - forwardedRef: forwardedRef, - }) - : React.createElement('div', { - ref: forwardedRef, - }); - let ref = null; - const refSetter = value => { - ref = value; - }; - act(() => - ReactDOM.render( - React.createElement(Wrapper, { - forwardedRef: refSetter, - }), - document.createElement('div'), - ), - ); - expect(store).toMatchInlineSnapshot(` - [root] - ▸ - `); - const deepestedNodeID = global.agent.getIDForHostInstance(ref); - act(() => store.toggleIsCollapsed(deepestedNodeID, false)); - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - ▾ - ▾ - ▾ - ▾ -
- `); - const rootID = store.getElementIDAtIndex(0); - act(() => store.toggleIsCollapsed(rootID, true)); - expect(store).toMatchInlineSnapshot(` - [root] - ▸ - `); - act(() => store.toggleIsCollapsed(rootID, false)); - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - ▾ - ▾ - ▾ - ▾ -
- `); - const id = store.getElementIDAtIndex(1); - act(() => store.toggleIsCollapsed(id, true)); - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - ▸ - `); - act(() => store.toggleIsCollapsed(id, false)); - expect(store).toMatchInlineSnapshot(` - [root] - ▾ - ▾ - ▾ - ▾ - ▾ -
- `); - }); - } it('should support reordering of children', () => { const Root = ({children}) => React.createElement('div', null, children); const Component = () => React.createElement('div', null); diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js index 6a70f22db917c..24f97520ecc3d 100644 --- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js @@ -197,223 +197,6 @@ describe('ReactFunctionComponent', () => { .rejects.toThrowError(); }); - // @gate !enableRefAsProp || !__DEV__ - it('should warn when given a string ref', async () => { - function Indirection(props) { - return
{props.children}
; - } - - class ParentUsingStringRef extends React.Component { - render() { - return ( - - - - ); - } - } - - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Function components cannot be given refs. ' + - 'Attempts to access this ref will fail. ' + - 'Did you mean to use React.forwardRef()?\n\n' + - 'Check the render method ' + - 'of `ParentUsingStringRef`.\n' + - ' in FunctionComponent (at **)\n' + - ' in div (at **)\n' + - ' in Indirection (at **)\n' + - ' in ParentUsingStringRef (at **)', - ); - - // No additional warnings should be logged - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }); - - // @gate !enableRefAsProp || !__DEV__ - it('should warn when given a function ref', async () => { - function Indirection(props) { - return
{props.children}
; - } - - const ref = jest.fn(); - class ParentUsingFunctionRef extends React.Component { - render() { - return ( - - - - ); - } - } - - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Function components cannot be given refs. ' + - 'Attempts to access this ref will fail. ' + - 'Did you mean to use React.forwardRef()?\n\n' + - 'Check the render method ' + - 'of `ParentUsingFunctionRef`.\n' + - ' in FunctionComponent (at **)\n' + - ' in div (at **)\n' + - ' in Indirection (at **)\n' + - ' in ParentUsingFunctionRef (at **)', - ); - expect(ref).not.toHaveBeenCalled(); - - // No additional warnings should be logged - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }); - - // @gate !enableRefAsProp || !__DEV__ - it('deduplicates ref warnings based on element or owner', async () => { - // When owner uses JSX, we can use exact line location to dedupe warnings - class AnonymousParentUsingJSX extends React.Component { - render() { - return {}} />; - } - } - - let instance1; - - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - - await act(() => { - root.render( - (instance1 = current)} />, - ); - }); - }).toErrorDev('Function components cannot be given refs.'); - // Should be deduped (offending element is on the same line): - instance1.forceUpdate(); - // Should also be deduped (offending element is on the same line): - let container = document.createElement('div'); - let root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - - // When owner doesn't use JSX, and is anonymous, we warn once per internal instance. - class AnonymousParentNotUsingJSX extends React.Component { - render() { - return React.createElement(FunctionComponent, { - name: 'A', - ref: () => {}, - }); - } - } - - let instance2; - await expect(async () => { - container = document.createElement('div'); - root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - (instance2 = current)} />, - ); - }); - }).toErrorDev('Function components cannot be given refs.'); - // Should be deduped (same internal instance, no additional warnings) - instance2.forceUpdate(); - // Could not be differentiated (since owner is anonymous and no source location) - container = document.createElement('div'); - root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - - // When owner doesn't use JSX, but is named, we warn once per owner name - class NamedParentNotUsingJSX extends React.Component { - render() { - return React.createElement(FunctionComponent, { - name: 'A', - ref: () => {}, - }); - } - } - let instance3; - await expect(async () => { - container = document.createElement('div'); - root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - (instance3 = current)} />, - ); - }); - }).toErrorDev('Function components cannot be given refs.'); - // Should be deduped (same owner name, no additional warnings): - instance3.forceUpdate(); - // Should also be deduped (same owner name, no additional warnings): - container = document.createElement('div'); - root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }); - - // This guards against a regression caused by clearing the current debug fiber. - // https://github.com/facebook/react/issues/10831 - // @gate !disableLegacyContext || !__DEV__ - // @gate !enableRefAsProp || !__DEV__ - it('should warn when giving a function ref with context', async () => { - function Child() { - return null; - } - Child.contextTypes = { - foo: PropTypes.string, - }; - - class Parent extends React.Component { - static childContextTypes = { - foo: PropTypes.string, - }; - getChildContext() { - return { - foo: 'bar', - }; - } - render() { - return ; - } - } - - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Function components cannot be given refs. ' + - 'Attempts to access this ref will fail. ' + - 'Did you mean to use React.forwardRef()?\n\n' + - 'Check the render method ' + - 'of `Parent`.\n' + - ' in Child (at **)\n' + - ' in Parent (at **)', - ); - }); - it('should use correct name in key warning', async () => { function Child() { return
{[]}
; diff --git a/packages/react-dom/src/__tests__/refs-test.js b/packages/react-dom/src/__tests__/refs-test.js index 1b081bff73b02..80ea8d1e26b32 100644 --- a/packages/react-dom/src/__tests__/refs-test.js +++ b/packages/react-dom/src/__tests__/refs-test.js @@ -369,24 +369,6 @@ describe('ref swapping', () => { }); }).rejects.toThrow('Expected ref to be a function'); }); - - // @gate !enableRefAsProp && www - it('undefined ref on manually inlined React element triggers error', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render({ - $$typeof: Symbol.for('react.element'), - type: 'div', - props: { - ref: undefined, - }, - key: null, - }); - }); - }).rejects.toThrow('Expected ref to be a function'); - }); }); describe('root level refs', () => { diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index b9454b8ec2339..3e95e537e9ddd 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -35,11 +35,7 @@ import { ConcurrentRoot, LegacyRoot, } from 'react-reconciler/constants'; -import { - enableRefAsProp, - disableLegacyMode, - disableStringRefs, -} from 'shared/ReactFeatureFlags'; +import {disableLegacyMode, disableStringRefs} from 'shared/ReactFeatureFlags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactVersion from 'shared/ReactVersion'; @@ -833,7 +829,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { let currentEventPriority = DefaultEventPriority; function createJSXElementForTestComparison(type, props) { - if (__DEV__ && enableRefAsProp) { + if (__DEV__) { const element = { type: type, $$typeof: REACT_ELEMENT_TYPE, diff --git a/packages/react-reconciler/src/ReactChildFiber.js b/packages/react-reconciler/src/ReactChildFiber.js index fe92520b1b2e4..96512d9dce282 100644 --- a/packages/react-reconciler/src/ReactChildFiber.js +++ b/packages/react-reconciler/src/ReactChildFiber.js @@ -45,7 +45,6 @@ import { } from './ReactWorkTags'; import isArray from 'shared/isArray'; import { - enableRefAsProp, enableAsyncIterableChildren, disableLegacyMode, enableOwnerStacks, @@ -239,21 +238,6 @@ function validateFragmentProps( break; } } - - if (!enableRefAsProp && element.ref !== null) { - if (fiber === null) { - // For unkeyed root fragments there's no Fiber. We create a fake one just for - // error stack handling. - fiber = createFiberFromElement(element, returnFiber.mode, 0); - if (__DEV__) { - fiber._debugInfo = currentDebugInfo; - } - fiber.return = returnFiber; - } - runWithFiberInDEV(fiber, () => { - console.error('Invalid attribute `ref` supplied to `React.Fragment`.'); - }); - } } } @@ -266,27 +250,14 @@ function unwrapThenable(thenable: Thenable): T { return trackUsedThenable(thenableState, thenable, index); } -function coerceRef( - returnFiber: Fiber, - current: Fiber | null, - workInProgress: Fiber, - element: ReactElement, -): void { - let ref; - if (enableRefAsProp) { - // TODO: This is a temporary, intermediate step. When enableRefAsProp is on, - // we should resolve the `ref` prop during the begin phase of the component - // it's attached to (HostComponent, ClassComponent, etc). - const refProp = element.props.ref; - ref = refProp !== undefined ? refProp : null; - } else { - // Old behavior. - ref = element.ref; - } - - // TODO: If enableRefAsProp is on, we shouldn't use the `ref` field. We +function coerceRef(workInProgress: Fiber, element: ReactElement): void { + // TODO: This is a temporary, intermediate step. Now that enableRefAsProp is on, + // we should resolve the `ref` prop during the begin phase of the component + // it's attached to (HostComponent, ClassComponent, etc). + const refProp = element.props.ref; + // TODO: With enableRefAsProp now rolled out, we shouldn't use the `ref` field. We // should always read the ref from the prop. - workInProgress.ref = ref; + workInProgress.ref = refProp !== undefined ? refProp : null; } function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) { @@ -569,7 +540,7 @@ function createChildReconciler( ) { // Move based on index const existing = useFiber(current, element.props); - coerceRef(returnFiber, current, existing, element); + coerceRef(existing, element); existing.return = returnFiber; if (__DEV__) { existing._debugOwner = element._owner; @@ -580,7 +551,7 @@ function createChildReconciler( } // Insert const created = createFiberFromElement(element, returnFiber.mode, lanes); - coerceRef(returnFiber, current, created, element); + coerceRef(created, element); created.return = returnFiber; if (__DEV__) { created._debugInfo = currentDebugInfo; @@ -693,7 +664,7 @@ function createChildReconciler( returnFiber.mode, lanes, ); - coerceRef(returnFiber, null, created, newChild); + coerceRef(created, newChild); created.return = returnFiber; if (__DEV__) { const prevDebugInfo = pushDebugInfo(newChild._debugInfo); @@ -1684,7 +1655,7 @@ function createChildReconciler( ) { deleteRemainingChildren(returnFiber, child.sibling); const existing = useFiber(child, element.props); - coerceRef(returnFiber, child, existing, element); + coerceRef(existing, element); existing.return = returnFiber; if (__DEV__) { existing._debugOwner = element._owner; @@ -1722,7 +1693,7 @@ function createChildReconciler( return created; } else { const created = createFiberFromElement(element, returnFiber.mode, lanes); - coerceRef(returnFiber, currentFirstChild, created, element); + coerceRef(created, element); created.return = returnFiber; if (__DEV__) { created._debugInfo = currentDebugInfo; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index f4ce6e849b25e..efb34826c970d 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -108,7 +108,6 @@ import { enableAsyncActions, enablePostpone, enableRenderableContext, - enableRefAsProp, disableLegacyMode, disableDefaultPropsExceptForClasses, disableStringRefs, @@ -125,10 +124,7 @@ import { REACT_MEMO_TYPE, getIteratorFn, } from 'shared/ReactSymbols'; -import { - getCurrentFiberOwnerNameInDevOrNull, - setCurrentFiber, -} from './ReactCurrentFiber'; +import {setCurrentFiber} from './ReactCurrentFiber'; import { resolveFunctionForHotReloading, resolveForwardRefForHotReloading, @@ -319,7 +315,6 @@ let didWarnAboutBadClass; let didWarnAboutContextTypeOnFunctionComponent; let didWarnAboutContextTypes; let didWarnAboutGetDerivedStateOnFunctionComponent; -let didWarnAboutFunctionRefs; export let didWarnAboutReassigningProps: boolean; let didWarnAboutRevealOrder; let didWarnAboutTailOptions; @@ -330,7 +325,6 @@ if (__DEV__) { didWarnAboutContextTypeOnFunctionComponent = ({}: {[string]: boolean}); didWarnAboutContextTypes = ({}: {[string]: boolean}); didWarnAboutGetDerivedStateOnFunctionComponent = ({}: {[string]: boolean}); - didWarnAboutFunctionRefs = ({}: {[string]: boolean}); didWarnAboutReassigningProps = false; didWarnAboutRevealOrder = ({}: {[empty]: boolean}); didWarnAboutTailOptions = ({}: {[string]: boolean}); @@ -416,7 +410,7 @@ function updateForwardRef( const ref = workInProgress.ref; let propsWithoutRef; - if (enableRefAsProp && 'ref' in nextProps) { + if ('ref' in nextProps) { // `ref` is just a prop now, but `forwardRef` expects it to not appear in // the props object. This used to happen in the JSX runtime, but now we do // it here. @@ -1954,25 +1948,6 @@ function validateFunctionComponentInDev(workInProgress: Fiber, Component: any) { Component.displayName || Component.name || 'Component', ); } - if (!enableRefAsProp && workInProgress.ref !== null) { - let info = ''; - const componentName = getComponentNameFromType(Component) || 'Unknown'; - const ownerName = getCurrentFiberOwnerNameInDevOrNull(); - if (ownerName) { - info += '\n\nCheck the render method of `' + ownerName + '`.'; - } - - const warningKey = componentName + '|' + (ownerName || ''); - if (!didWarnAboutFunctionRefs[warningKey]) { - didWarnAboutFunctionRefs[warningKey] = true; - console.error( - 'Function components cannot be given refs. ' + - 'Attempts to access this ref will fail. ' + - 'Did you mean to use React.forwardRef()?%s', - info, - ); - } - } if ( !disableDefaultPropsExceptForClasses && diff --git a/packages/react-reconciler/src/ReactFiberClassComponent.js b/packages/react-reconciler/src/ReactFiberClassComponent.js index 79c516eacf117..c32525702e944 100644 --- a/packages/react-reconciler/src/ReactFiberClassComponent.js +++ b/packages/react-reconciler/src/ReactFiberClassComponent.js @@ -23,7 +23,6 @@ import { enableDebugTracing, enableSchedulingProfiler, enableLazyContextPropagation, - enableRefAsProp, disableDefaultPropsExceptForClasses, } from 'shared/ReactFeatureFlags'; import ReactStrictModeWarnings from './ReactStrictModeWarnings'; @@ -1252,14 +1251,12 @@ export function resolveClassComponentProps( ): Object { let newProps = baseProps; - if (enableRefAsProp) { - // Remove ref from the props object, if it exists. - if ('ref' in baseProps) { - newProps = ({}: any); - for (const propName in baseProps) { - if (propName !== 'ref') { - newProps[propName] = baseProps[propName]; - } + // Remove ref from the props object, if it exists. + if ('ref' in baseProps) { + newProps = ({}: any); + for (const propName in baseProps) { + if (propName !== 'ref') { + newProps[propName] = baseProps[propName]; } } } diff --git a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js index 2a0590af3171d..8fd5206c94ae4 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js @@ -85,7 +85,6 @@ describe('ReactFiberRefs', () => { expect(ref2.current).not.toBe(null); }); - // @gate enableRefAsProp // @gate !disableStringRefs it('string ref props are converted to function refs', async () => { let refProp; @@ -105,7 +104,7 @@ describe('ReactFiberRefs', () => { const root = ReactNoop.createRoot(); await act(() => root.render()); - // When string refs aren't disabled, and enableRefAsProp is on, string refs + // When string refs aren't disabled, string refs // the receiving component receives a callback ref, not the original string. // This behavior should never be shipped to open source; it's only here to // allow Meta to keep using string refs temporarily while they finish diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js index 37e885cd47900..81f892b48e358 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js @@ -1299,20 +1299,7 @@ describe('ReactIncrementalSideEffects', () => { ReactNoop.render(); - if (gate(flags => flags.enableRefAsProp)) { - await waitForAll([]); - } else { - await expect(async () => await waitForAll([])).toErrorDev( - 'Function components cannot be given refs. ' + - 'Attempts to access this ref will fail. ' + - 'Did you mean to use React.forwardRef()?\n\n' + - 'Check the render method ' + - 'of `Foo`.\n' + - ' in FunctionComponent (at **)\n' + - ' in div (at **)\n' + - ' in Foo (at **)', - ); - } + await waitForAll([]); expect(ops).toEqual([ classInstance, diff --git a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js index 8526fb5b19cd6..ddcd751957100 100644 --- a/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js @@ -1236,30 +1236,6 @@ describe('ReactLazy', () => { expect(root).toMatchRenderedOutput('2'); }); - // @gate !enableRefAsProp || !__DEV__ - it('warns about ref on functions for lazy-loaded components', async () => { - const Foo = props =>
; - const LazyFoo = lazy(() => { - return fakeImport(Foo); - }); - - const ref = React.createRef(); - ReactTestRenderer.create( - }> - - , - { - unstable_isConcurrent: true, - }, - ); - - await waitForAll(['Loading...']); - await resolveFakeImport(Foo); - await expect(async () => { - await waitForAll([]); - }).toErrorDev('Function components cannot be given refs'); - }); - it('should error with a component stack naming the resolved component', async () => { let componentStackMessage; diff --git a/packages/react-reconciler/src/__tests__/ReactMemo-test.js b/packages/react-reconciler/src/__tests__/ReactMemo-test.js index c4d50631ec8ba..5fdf14af4d37b 100644 --- a/packages/react-reconciler/src/__tests__/ReactMemo-test.js +++ b/packages/react-reconciler/src/__tests__/ReactMemo-test.js @@ -44,43 +44,6 @@ describe('memo', () => { return {default: result}; } - // @gate !enableRefAsProp || !__DEV__ - it('warns when giving a ref (simple)', async () => { - // This test lives outside sharedTests because the wrappers don't forward - // refs properly, and they end up affecting the current owner which is used - // by the warning (making the messages not line up). - function App() { - return null; - } - App = React.memo(App); - function Outer() { - return {}} />; - } - ReactNoop.render(); - await expect(async () => await waitForAll([])).toErrorDev([ - 'Function components cannot be given refs. Attempts to access ' + - 'this ref will fail.', - ]); - }); - - // @gate !enableRefAsProp || !__DEV__ - it('warns when giving a ref (complex)', async () => { - function App() { - return null; - } - // A custom compare function means this won't use SimpleMemoComponent (as of this writing) - // SimpleMemoComponent is unobservable tho, so we can't check :) - App = React.memo(App, () => false); - function Outer() { - return {}} />; - } - ReactNoop.render(); - await expect(async () => await waitForAll([])).toErrorDev([ - 'Function components cannot be given refs. Attempts to access ' + - 'this ref will fail.', - ]); - }); - // Tests should run against both the lazy and non-lazy versions of `memo`. // To make the tests work for both versions, we wrap the non-lazy version in // a lazy function component. diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index f384908720a33..7b881fdbe8cce 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -160,7 +160,6 @@ import { enablePostpone, enableHalt, enableRenderableContext, - enableRefAsProp, disableDefaultPropsExceptForClasses, enableAsyncIterableChildren, disableStringRefs, @@ -1671,14 +1670,12 @@ export function resolveClassComponentProps( ): Object { let newProps = baseProps; - if (enableRefAsProp) { - // Remove ref from the props object, if it exists. - if ('ref' in baseProps) { - newProps = ({}: any); - for (const propName in baseProps) { - if (propName !== 'ref') { - newProps[propName] = baseProps[propName]; - } + // Remove ref from the props object, if it exists. + if ('ref' in baseProps) { + newProps = ({}: any); + for (const propName in baseProps) { + if (propName !== 'ref') { + newProps[propName] = baseProps[propName]; } } } @@ -1973,7 +1970,7 @@ function renderForwardRef( ref: any, ): void { let propsWithoutRef; - if (enableRefAsProp && 'ref' in props) { + if ('ref' in props) { // `ref` is just a prop now, but `forwardRef` expects it to not appear in // the props object. This used to happen in the JSX runtime, but now we do // it here. @@ -2595,16 +2592,10 @@ function retryNode(request: Request, task: Task): void { const key = element.key; const props = element.props; - let ref; - if (enableRefAsProp) { - // TODO: This is a temporary, intermediate step. Once the feature - // flag is removed, we should get the ref off the props object right - // before using it. - const refProp = props.ref; - ref = refProp !== undefined ? refProp : null; - } else { - ref = element.ref; - } + // TODO: We should get the ref off the props object right before using + // it. + const refProp = props.ref; + const ref = refProp !== undefined ? refProp : null; const debugTask: null | ConsoleTask = __DEV__ && enableOwnerStacks ? task.debugTask : null; diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 75d5947baecef..8b69c7a8036ef 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -18,7 +18,6 @@ import { enablePostpone, enableHalt, enableTaint, - enableRefAsProp, enableServerComponentLogs, enableOwnerStacks, } from 'shared/ReactFeatureFlags'; @@ -2512,16 +2511,10 @@ function renderModelDestructive( } const props = element.props; - let ref; - if (enableRefAsProp) { - // TODO: This is a temporary, intermediate step. Once the feature - // flag is removed, we should get the ref off the props object right - // before using it. - const refProp = props.ref; - ref = refProp !== undefined ? refProp : null; - } else { - ref = element.ref; - } + // TODO: We should get the ref off the props object right before using + // it. + const refProp = props.ref; + const ref = refProp !== undefined ? refProp : null; // Attempt to render the Server Component. diff --git a/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js b/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js index f596183589705..551c10fb5f3df 100644 --- a/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js +++ b/packages/react-test-renderer/src/__tests__/ReactTestRenderer-test.internal.js @@ -386,39 +386,6 @@ describe('ReactTestRenderer', () => { expect(log).toEqual([null]); }); - // @gate !enableRefAsProp || !__DEV__ - it('warns correctly for refs on SFCs', async () => { - function Bar() { - return
Hello, world
; - } - class Foo extends React.Component { - fooRef = React.createRef(); - render() { - return ; - } - } - class Baz extends React.Component { - bazRef = React.createRef(); - render() { - return
; - } - } - await act(() => { - ReactTestRenderer.create(); - }); - await expect(async () => { - await act(() => { - ReactTestRenderer.create(); - }); - }).toErrorDev( - 'Function components cannot be given refs. Attempts ' + - 'to access this ref will fail. ' + - 'Did you mean to use React.forwardRef()?\n' + - ' in Bar (at **)\n' + - ' in Foo (at **)', - ); - }); - it('allows an optional createNodeMock function', async () => { const mockDivInstance = {appendChild: () => {}}; const mockInputInstance = {focus: () => {}}; @@ -1226,11 +1193,9 @@ describe('ReactTestRenderer', () => { { instance: null, nodeType: 'host', - props: gate(flags => flags.enableRefAsProp) - ? { - ref: refFn, - } - : {}, + props: { + ref: refFn, + }, rendered: [], type: 'span', }, diff --git a/packages/react/src/__tests__/ReactCreateElement-test.js b/packages/react/src/__tests__/ReactCreateElement-test.js index 51012166af260..3ab5c34c3304d 100644 --- a/packages/react/src/__tests__/ReactCreateElement-test.js +++ b/packages/react/src/__tests__/ReactCreateElement-test.js @@ -37,11 +37,7 @@ describe('ReactCreateElement', () => { const element = React.createElement(ComponentClass); expect(element.type).toBe(ComponentClass); expect(element.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); if (__DEV__) { expect(Object.isFrozen(element)).toBe(true); expect(Object.isFrozen(element.props)).toBe(true); @@ -90,45 +86,11 @@ describe('ReactCreateElement', () => { ); }); - // @gate !enableRefAsProp || !__DEV__ - it('should warn when `ref` is being accessed', async () => { - class Child extends React.Component { - render() { - return React.createElement('div', null, this.props.ref); - } - } - class Parent extends React.Component { - render() { - return React.createElement( - 'div', - null, - React.createElement(Child, {ref: React.createRef()}), - ); - } - } - const root = ReactDOMClient.createRoot(document.createElement('div')); - - await expect(async () => { - await act(() => { - root.render(React.createElement(Parent)); - }); - }).toErrorDev( - 'Child: `ref` is not a prop. Trying to access it will result ' + - 'in `undefined` being returned. If you need to access the same ' + - 'value within the child component, you should pass it as a different ' + - 'prop. (https://react.dev/link/special-props)', - ); - }); - it('allows a string to be passed as the type', () => { const element = React.createElement('div'); expect(element.type).toBe('div'); expect(element.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); if (__DEV__) { expect(Object.isFrozen(element)).toBe(true); expect(Object.isFrozen(element.props)).toBe(true); @@ -179,20 +141,13 @@ describe('ReactCreateElement', () => { foo: '56', }); expect(element.type).toBe(ComponentClass); - if (gate(flags => flags.enableRefAsProp)) { - expect(() => expect(element.ref).toBe(ref)).toErrorDev( - 'Accessing element.ref was removed in React 19', - {withoutStack: true}, - ); - const expectation = {foo: '56', ref}; - Object.freeze(expectation); - expect(element.props).toEqual(expectation); - } else { - const expectation = {foo: '56'}; - Object.freeze(expectation); - expect(element.props).toEqual(expectation); - expect(element.ref).toBe(ref); - } + expect(() => expect(element.ref).toBe(ref)).toErrorDev( + 'Accessing element.ref was removed in React 19', + {withoutStack: true}, + ); + const expectation = {foo: '56', ref}; + Object.freeze(expectation); + expect(element.props).toEqual(expectation); }); it('extracts null key', () => { @@ -218,11 +173,7 @@ describe('ReactCreateElement', () => { const element = React.createElement(ComponentClass, props); expect(element.type).toBe(ComponentClass); expect(element.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); if (__DEV__) { expect(Object.isFrozen(element)).toBe(true); expect(Object.isFrozen(element.props)).toBe(true); @@ -234,11 +185,7 @@ describe('ReactCreateElement', () => { const elementA = React.createElement('div'); const elementB = React.createElement('div', elementA.props); expect(elementB.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(elementB.ref).toBe(null); - } else { - expect(elementB.ref).toBe(null); - } + expect(elementB.ref).toBe(null); }); it('coerces the key to a string', () => { @@ -248,11 +195,7 @@ describe('ReactCreateElement', () => { }); expect(element.type).toBe(ComponentClass); expect(element.key).toBe('12'); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); if (__DEV__) { expect(Object.isFrozen(element)).toBe(true); expect(Object.isFrozen(element.props)).toBe(true); diff --git a/packages/react/src/__tests__/ReactElementClone-test.js b/packages/react/src/__tests__/ReactElementClone-test.js index 1acf56749ed65..435af8e11804f 100644 --- a/packages/react/src/__tests__/ReactElementClone-test.js +++ b/packages/react/src/__tests__/ReactElementClone-test.js @@ -212,11 +212,7 @@ describe('ReactElementClone', () => { ref: this.xyzRef, }); expect(clone.key).toBe('xyz'); - if (gate(flags => flags.enableRefAsProp)) { - expect(clone.props.ref).toBe(this.xyzRef); - } else { - expect(clone.ref).toBe(this.xyzRef); - } + expect(clone.props.ref).toBe(this.xyzRef); return
{clone}
; } } @@ -274,17 +270,13 @@ describe('ReactElementClone', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); await act(() => root.render()); - if (gate(flags => flags.enableRefAsProp && flags.disableStringRefs)) { + if (gate(flags => flags.disableStringRefs)) { expect(component.childRef).toEqual({current: null}); expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); - } else if ( - gate(flags => !flags.enableRefAsProp && !flags.disableStringRefs) - ) { + } else if (gate(flags => false)) { expect(component.childRef).toEqual({current: null}); expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); - } else if ( - gate(flags => flags.enableRefAsProp && !flags.disableStringRefs) - ) { + } else if (gate(flags => !flags.disableStringRefs)) { expect(component.childRef).toEqual({current: null}); expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); } else { @@ -397,11 +389,7 @@ describe('ReactElementClone', () => { const elementA = React.createElement('div'); const elementB = React.cloneElement(elementA, elementA.props); expect(elementB.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(elementB.ref).toBe(null); - } else { - expect(elementB.ref).toBe(null); - } + expect(elementB.ref).toBe(null); }); it('should ignore undefined key and ref', () => { @@ -418,21 +406,17 @@ describe('ReactElementClone', () => { const clone = React.cloneElement(element, props); expect(clone.type).toBe(ComponentClass); expect(clone.key).toBe('12'); - if (gate(flags => flags.enableRefAsProp && flags.disableStringRefs)) { + if (gate(flags => flags.disableStringRefs)) { expect(clone.props.ref).toBe('34'); expect(() => expect(clone.ref).toBe('34')).toErrorDev( 'Accessing element.ref was removed in React 19', {withoutStack: true}, ); expect(clone.props).toEqual({foo: 'ef', ref: '34'}); - } else if ( - gate(flags => !flags.enableRefAsProp && !flags.disableStringRefs) - ) { + } else if (gate(flags => false)) { expect(clone.ref).toBe(element.ref); expect(clone.props).toEqual({foo: 'ef'}); - } else if ( - gate(flags => flags.enableRefAsProp && !flags.disableStringRefs) - ) { + } else if (gate(flags => !flags.disableStringRefs)) { expect(() => { expect(clone.ref).toBe(element.ref); }).toErrorDev('Accessing element.ref was removed in React 19', { @@ -462,14 +446,8 @@ describe('ReactElementClone', () => { const clone = React.cloneElement(element, props); expect(clone.type).toBe(ComponentClass); expect(clone.key).toBe('null'); - if (gate(flags => flags.enableRefAsProp)) { - expect(clone.ref).toBe(null); - expect(clone.props).toEqual({foo: 'ef', ref: null}); - } else { - expect(clone.ref).toBe(null); - expect(clone.props).toEqual({foo: 'ef'}); - } - + expect(clone.ref).toBe(null); + expect(clone.props).toEqual({foo: 'ef', ref: null}); if (__DEV__) { expect(Object.isFrozen(element)).toBe(true); expect(Object.isFrozen(element.props)).toBe(true); diff --git a/packages/react/src/__tests__/ReactJSXElementValidator-test.js b/packages/react/src/__tests__/ReactJSXElementValidator-test.js index f827a52bc59ca..12e54e5c969cc 100644 --- a/packages/react/src/__tests__/ReactJSXElementValidator-test.js +++ b/packages/react/src/__tests__/ReactJSXElementValidator-test.js @@ -248,23 +248,13 @@ describe('ReactJSXElementValidator', () => { } } - if (gate(flags => flags.enableRefAsProp)) { - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }).toErrorDev('Invalid prop `ref` supplied to `React.Fragment`.'); - } else { - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(); - }); - }).toErrorDev('Invalid attribute `ref` supplied to `React.Fragment`.'); - } + await expect(async () => { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + }).toErrorDev('Invalid prop `ref` supplied to `React.Fragment`.'); }); it('does not warn for fragments of multiple elements without keys', async () => { diff --git a/packages/react/src/__tests__/ReactJSXRuntime-test.js b/packages/react/src/__tests__/ReactJSXRuntime-test.js index 90316cbd70601..e3de4dbf5ead5 100644 --- a/packages/react/src/__tests__/ReactJSXRuntime-test.js +++ b/packages/react/src/__tests__/ReactJSXRuntime-test.js @@ -244,34 +244,6 @@ describe('ReactJSXRuntime', () => { ); }); - // @gate !enableRefAsProp || !__DEV__ - it('should warn when `ref` is being accessed', async () => { - const container = document.createElement('div'); - class Child extends React.Component { - render() { - return JSXRuntime.jsx('div', {children: this.props.ref}); - } - } - class Parent extends React.Component { - render() { - return JSXRuntime.jsx('div', { - children: JSXRuntime.jsx(Child, {ref: React.createRef()}), - }); - } - } - await expect(async () => { - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(JSXRuntime.jsx(Parent, {})); - }); - }).toErrorDev( - 'Child: `ref` is not a prop. Trying to access it will result ' + - 'in `undefined` being returned. If you need to access the same ' + - 'value within the child component, you should pass it as a different ' + - 'prop. (https://react.dev/link/special-props)', - ); - }); - it('should warn when unkeyed children are passed to jsx', async () => { const container = document.createElement('div'); @@ -377,7 +349,6 @@ describe('ReactJSXRuntime', () => { expect(didCall).toBe(false); }); - // @gate enableRefAsProp it('does not clone props object if key and ref is not spread', async () => { const config = { foo: 'foo', diff --git a/packages/react/src/__tests__/ReactJSXTransformIntegration-test.js b/packages/react/src/__tests__/ReactJSXTransformIntegration-test.js index 22480f1a7ef63..f0caf6b494ae1 100644 --- a/packages/react/src/__tests__/ReactJSXTransformIntegration-test.js +++ b/packages/react/src/__tests__/ReactJSXTransformIntegration-test.js @@ -55,11 +55,7 @@ describe('ReactJSXTransformIntegration', () => { const element = ; expect(element.type).toBe(Component); expect(element.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); const expectation = {}; Object.freeze(expectation); expect(element.props).toEqual(expectation); @@ -69,11 +65,7 @@ describe('ReactJSXTransformIntegration', () => { const element =
; expect(element.type).toBe('div'); expect(element.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); const expectation = {}; Object.freeze(expectation); expect(element.props).toEqual(expectation); @@ -84,11 +76,7 @@ describe('ReactJSXTransformIntegration', () => { const element = ; expect(element.type).toBe('div'); expect(element.key).toBe(null); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); const expectation = {}; Object.freeze(expectation); expect(element.props).toEqual(expectation); @@ -124,31 +112,20 @@ describe('ReactJSXTransformIntegration', () => { const ref = React.createRef(); const element = ; expect(element.type).toBe(Component); - if (gate(flags => flags.enableRefAsProp)) { - expect(() => expect(element.ref).toBe(ref)).toErrorDev( - 'Accessing element.ref was removed in React 19', - {withoutStack: true}, - ); - const expectation = {foo: '56', ref}; - Object.freeze(expectation); - expect(element.props).toEqual(expectation); - } else { - const expectation = {foo: '56'}; - Object.freeze(expectation); - expect(element.props).toEqual(expectation); - expect(element.ref).toBe(ref); - } + expect(() => expect(element.ref).toBe(ref)).toErrorDev( + 'Accessing element.ref was removed in React 19', + {withoutStack: true}, + ); + const expectation = {foo: '56', ref}; + Object.freeze(expectation); + expect(element.props).toEqual(expectation); }); it('coerces the key to a string', () => { const element = ; expect(element.type).toBe(Component); expect(element.key).toBe('12'); - if (gate(flags => flags.enableRefAsProp)) { - expect(element.ref).toBe(null); - } else { - expect(element.ref).toBe(null); - } + expect(element.ref).toBe(null); const expectation = {foo: '56'}; Object.freeze(expectation); expect(element.props).toEqual(expectation); diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index 893806def2c47..1d1848e3418b8 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -20,7 +20,6 @@ import isValidElementType from 'shared/isValidElementType'; import isArray from 'shared/isArray'; import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame'; import { - enableRefAsProp, disableStringRefs, disableDefaultPropsExceptForClasses, enableOwnerStacks, @@ -72,7 +71,6 @@ function getOwner() { } let specialPropKeyWarningShown; -let specialPropRefWarningShown; let didWarnAboutStringRefs; let didWarnAboutElementRef; let didWarnAboutOldJSXRuntime; @@ -82,7 +80,7 @@ if (__DEV__ || enableLogStringRefsProd) { didWarnAboutElementRef = {}; } -const enableFastJSXWithoutStringRefs = enableRefAsProp && disableStringRefs; +const enableFastJSXWithoutStringRefs = disableStringRefs; function hasValidRef(config) { if (__DEV__) { @@ -159,30 +157,6 @@ function defineKeyPropWarningGetter(props, displayName) { } } -function defineRefPropWarningGetter(props, displayName) { - if (!enableRefAsProp) { - if (__DEV__) { - const warnAboutAccessingRef = function () { - if (!specialPropRefWarningShown) { - specialPropRefWarningShown = true; - console.error( - '%s: `ref` is not a prop. Trying to access it will result ' + - 'in `undefined` being returned. If you need to access the same ' + - 'value within the child component, you should pass it as a different ' + - 'prop. (https://react.dev/link/special-props)', - displayName, - ); - } - }; - warnAboutAccessingRef.isReactWarning = true; - Object.defineProperty(props, 'ref', { - get: warnAboutAccessingRef, - configurable: true, - }); - } - } -} - function elementRefGetterWithDeprecationWarning() { if (__DEV__) { const componentName = getComponentNameFromType(this.type); @@ -225,7 +199,6 @@ function elementRefGetterWithDeprecationWarning() { function ReactElement( type, key, - _ref, self, source, owner, @@ -233,24 +206,18 @@ function ReactElement( debugStack, debugTask, ) { - let ref; - if (enableRefAsProp) { - // When enableRefAsProp is on, ignore whatever was passed as the ref - // argument and treat `props.ref` as the source of truth. The only thing we - // use this for is `element.ref`, which will log a deprecation warning on - // access. In the next release, we can remove `element.ref` as well as the - // `ref` argument. - const refProp = props.ref; + // Ignore whatever was passed as the ref argument and treat `props.ref` as + // the source of truth. The only thing we use this for is `element.ref`, + // which will log a deprecation warning on access. In the next release, we + // can remove `element.ref` as well as the `ref` argument. + const refProp = props.ref; - // An undefined `element.ref` is coerced to `null` for - // backwards compatibility. - ref = refProp !== undefined ? refProp : null; - } else { - ref = _ref; - } + // An undefined `element.ref` is coerced to `null` for + // backwards compatibility. + const ref = refProp !== undefined ? refProp : null; let element; - if (__DEV__ && enableRefAsProp) { + if (__DEV__) { // In dev, make `ref` a non-enumerable property with a warning. It's non- // enumerable so that test matchers and serializers don't access it and // trigger the warning. @@ -380,7 +347,6 @@ function ReactElement( */ export function jsxProd(type, config, maybeKey) { let key = null; - let ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -402,19 +368,9 @@ export function jsxProd(type, config, maybeKey) { key = '' + config.key; } - if (hasValidRef(config)) { - if (!enableRefAsProp) { - ref = config.ref; - if (!disableStringRefs) { - ref = coerceStringRef(ref, getOwner(), type); - } - } - } - let props; if ( - (enableFastJSXWithoutStringRefs || - (enableRefAsProp && !('ref' in config))) && + (enableFastJSXWithoutStringRefs || !('ref' in config)) && !('key' in config) ) { // If key was not spread in, we can reuse the original props object. This @@ -434,8 +390,8 @@ export function jsxProd(type, config, maybeKey) { props = {}; for (const propName in config) { // Skip over reserved prop names - if (propName !== 'key' && (enableRefAsProp || propName !== 'ref')) { - if (enableRefAsProp && !disableStringRefs && propName === 'ref') { + if (propName !== 'key') { + if (!disableStringRefs && propName === 'ref') { props.ref = coerceStringRef(config[propName], getOwner(), type); } else { props[propName] = config[propName]; @@ -459,7 +415,6 @@ export function jsxProd(type, config, maybeKey) { return ReactElement( type, key, - ref, undefined, undefined, getOwner(), @@ -662,7 +617,6 @@ function jsxDEVImpl( } let key = null; - let ref = null; // Currently, key can be spread in as a prop. This causes a potential // issue if key is also explicitly declared (ie.
@@ -684,22 +638,15 @@ function jsxDEVImpl( key = '' + config.key; } - if (hasValidRef(config)) { - if (!enableRefAsProp) { - ref = config.ref; - if (!disableStringRefs) { - ref = coerceStringRef(ref, getOwner(), type); - } - } - if (!disableStringRefs) { + if (!disableStringRefs) { + if (hasValidRef(config)) { warnIfStringRefCannotBeAutoConverted(config, self); } } let props; if ( - (enableFastJSXWithoutStringRefs || - (enableRefAsProp && !('ref' in config))) && + (enableFastJSXWithoutStringRefs || !('ref' in config)) && !('key' in config) ) { // If key was not spread in, we can reuse the original props object. This @@ -719,8 +666,8 @@ function jsxDEVImpl( props = {}; for (const propName in config) { // Skip over reserved prop names - if (propName !== 'key' && (enableRefAsProp || propName !== 'ref')) { - if (enableRefAsProp && !disableStringRefs && propName === 'ref') { + if (propName !== 'key') { + if (!disableStringRefs && propName === 'ref') { props.ref = coerceStringRef(config[propName], getOwner(), type); } else { props[propName] = config[propName]; @@ -741,23 +688,17 @@ function jsxDEVImpl( } } - if (key || (!enableRefAsProp && ref)) { + if (key) { const displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; - if (key) { - defineKeyPropWarningGetter(props, displayName); - } - if (!enableRefAsProp && ref) { - defineRefPropWarningGetter(props, displayName); - } + defineKeyPropWarningGetter(props, displayName); } return ReactElement( type, key, - ref, self, source, getOwner(), @@ -838,7 +779,6 @@ export function createElement(type, config, children) { const props = {}; let key = null; - let ref = null; if (config != null) { if (__DEV__) { @@ -861,15 +801,8 @@ export function createElement(type, config, children) { } } - if (hasValidRef(config)) { - if (!enableRefAsProp) { - ref = config.ref; - if (!disableStringRefs) { - ref = coerceStringRef(ref, getOwner(), type); - } - } - - if (__DEV__ && !disableStringRefs) { + if (__DEV__ && !disableStringRefs) { + if (hasValidRef(config)) { warnIfStringRefCannotBeAutoConverted(config, config.__self); } } @@ -886,7 +819,6 @@ export function createElement(type, config, children) { hasOwnProperty.call(config, propName) && // Skip over reserved prop names propName !== 'key' && - (enableRefAsProp || propName !== 'ref') && // Even though we don't use these anymore in the runtime, we don't want // them to appear as props, so in createElement we filter them out. // We don't have to do this in the jsx() runtime because the jsx() @@ -894,7 +826,7 @@ export function createElement(type, config, children) { propName !== '__self' && propName !== '__source' ) { - if (enableRefAsProp && !disableStringRefs && propName === 'ref') { + if (!disableStringRefs && propName === 'ref') { props.ref = coerceStringRef(config[propName], getOwner(), type); } else { props[propName] = config[propName]; @@ -931,24 +863,18 @@ export function createElement(type, config, children) { } } if (__DEV__) { - if (key || (!enableRefAsProp && ref)) { + if (key) { const displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; - if (key) { - defineKeyPropWarningGetter(props, displayName); - } - if (!enableRefAsProp && ref) { - defineRefPropWarningGetter(props, displayName); - } + defineKeyPropWarningGetter(props, displayName); } } return ReactElement( type, key, - ref, undefined, undefined, getOwner(), @@ -962,9 +888,6 @@ export function cloneAndReplaceKey(oldElement, newKey) { const clonedElement = ReactElement( oldElement.type, newKey, - // When enableRefAsProp is on, this argument is ignored. This check only - // exists to avoid the `ref` access warning. - enableRefAsProp ? null : oldElement.ref, undefined, undefined, !__DEV__ && disableStringRefs ? undefined : oldElement._owner, @@ -997,7 +920,6 @@ export function cloneElement(element, config, children) { // Reserved names are extracted let key = element.key; - let ref = enableRefAsProp ? null : element.ref; // Owner will be preserved, unless ref is overridden let owner = !__DEV__ && disableStringRefs ? undefined : element._owner; @@ -1005,13 +927,6 @@ export function cloneElement(element, config, children) { if (config != null) { if (hasValidRef(config)) { owner = __DEV__ || !disableStringRefs ? getOwner() : undefined; - if (!enableRefAsProp) { - // Silently steal the ref from the parent. - ref = config.ref; - if (!disableStringRefs) { - ref = coerceStringRef(ref, owner, element.type); - } - } } if (hasValidKey(config)) { if (__DEV__) { @@ -1034,7 +949,6 @@ export function cloneElement(element, config, children) { hasOwnProperty.call(config, propName) && // Skip over reserved prop names propName !== 'key' && - (enableRefAsProp || propName !== 'ref') && // ...and maybe these, too, though we currently rely on them for // warnings and debug information in dev. Need to decide if we're OK // with dropping them. In the jsx() runtime it's not an issue because @@ -1046,7 +960,7 @@ export function cloneElement(element, config, children) { // Undefined `ref` is ignored by cloneElement. We treat it the same as // if the property were missing. This is mostly for // backwards compatibility. - !(enableRefAsProp && propName === 'ref' && config.ref === undefined) + !(propName === 'ref' && config.ref === undefined) ) { if ( !disableDefaultPropsExceptForClasses && @@ -1056,7 +970,7 @@ export function cloneElement(element, config, children) { // Resolve default props props[propName] = defaultProps[propName]; } else { - if (enableRefAsProp && !disableStringRefs && propName === 'ref') { + if (!disableStringRefs && propName === 'ref') { props.ref = coerceStringRef(config[propName], owner, element.type); } else { props[propName] = config[propName]; @@ -1082,7 +996,6 @@ export function cloneElement(element, config, children) { const clonedElement = ReactElement( element.type, key, - ref, undefined, undefined, owner, diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 5a11217452e57..a0722c31382da 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -208,13 +208,8 @@ export const enableFilterEmptyStringAttributesDOM = true; // Disabled caching behavior of `react/cache` in client runtimes. export const disableClientCache = true; -// Subtle breaking changes to JSX runtime to make it faster, like passing `ref` -// as a normal prop instead of stripping it from the props object. - -// Passes `ref` as a normal prop instead of stripping it from the props object -// during element creation. -export const enableRefAsProp = true; export const disableStringRefs = true; + /** * If set to a function, the function will be called with the component name * and ref string. diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index de6ee64caad20..b4339c50a5f2f 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -73,7 +73,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerTimer = __PROFILE__; export const enableReactTestRendererWarning = false; -export const enableRefAsProp = true; export const enableRenderableContext = true; export const enableRetryLaneExpiration = false; export const enableSchedulingProfiler = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 7b5e29a8fcc33..ea670690a5a93 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -63,7 +63,6 @@ export const enableOwnerStacks = false; export const enablePersistedModeClonedFlag = false; export const enablePostpone = false; export const enableReactTestRendererWarning = false; -export const enableRefAsProp = true; export const enableRenderableContext = true; export const enableRetryLaneExpiration = false; export const enableSchedulingProfiler = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 2fe7b8a19a9d5..2eb241af6c293 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -91,7 +91,6 @@ export const enableSiblingPrerendering = false; // We really need to get rid of this whole module. Any test renderer specific // flags should be handled by the Fiber config. // const __NEXT_MAJOR__ = __EXPERIMENTAL__; -export const enableRefAsProp = true; export const disableStringRefs = true; export const disableLegacyMode = true; export const disableLegacyContext = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index ae2f868e1d49c..1d505aaf56b9d 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -56,7 +56,6 @@ export const enableProfilerCommitHooks = __PROFILE__; export const enableProfilerNestedUpdatePhase = __PROFILE__; export const enableProfilerTimer = __PROFILE__; export const enableReactTestRendererWarning = false; -export const enableRefAsProp = true; export const enableRenderableContext = true; export const enableRetryLaneExpiration = false; export const enableSchedulingProfiler = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 7d9c3818c8f1b..5c836b48fe2e9 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -83,7 +83,6 @@ export const disableClientCache = true; export const enableServerComponentLogs = true; export const enableInfiniteRenderLoopDetection = false; -export const enableRefAsProp = true; export const disableStringRefs = false; export const enableReactTestRendererWarning = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index ec572d86f5ae4..b86394ecf739b 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -101,8 +101,6 @@ export const enableLegacyHidden = true; export const enableComponentStackLocations = true; -export const enableRefAsProp = true; - export const disableTextareaChildren = __EXPERIMENTAL__; export const consoleManagedByDevToolsDuringStrictMode = true; From 33c7bd9ae3b4f998a477fe0ea8ebdf2f2ee8a144 Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 4 Nov 2024 15:30:02 -0500 Subject: [PATCH 335/426] Remove trim_trailing_whitespace from editorconfig (#31413) This setting breaks `toMatchInlineSnapshot` by removing whitespace in snapshots. --- .editorconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 07552cfff88ba..48d2b3d27e85a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,11 +8,9 @@ indent_size = 2 indent_style = space insert_final_newline = true max_line_length = 80 -trim_trailing_whitespace = true [*.md] max_line_length = 0 -trim_trailing_whitespace = false [COMMIT_EDITMSG] max_line_length = 0 From b81e6dd2dade4c2d43d44ce7c9bfa4e3053fc949 Mon Sep 17 00:00:00 2001 From: lauren Date: Tue, 5 Nov 2024 14:14:39 -0500 Subject: [PATCH 336/426] [cleanup] Remove compiler runtime-compat fixture library (#31430) There's no real reason to keep this around anymore now that the compiler beta is released and we have validated that react-compiler-runtime is [usable by libraries](https://www.npmjs.com/package/react-compiler-runtime?activeTab=dependents). Let's clean this up for now. --- compiler/fixtures/.gitkeep | 0 compiler/fixtures/runtime-compat/README.md | 1 - .../fixtures/runtime-compat/app-18/.gitignore | 24 - .../fixtures/runtime-compat/app-18/README.md | 50 - .../runtime-compat/app-18/eslint.config.js | 28 - .../fixtures/runtime-compat/app-18/index.html | 13 - .../runtime-compat/app-18/package.json | 32 - .../runtime-compat/app-18/public/vite.svg | 1 - .../runtime-compat/app-18/src/App.css | 42 - .../runtime-compat/app-18/src/App.tsx | 16 - .../app-18/src/assets/react.svg | 1 - .../runtime-compat/app-18/src/index.css | 68 - .../runtime-compat/app-18/src/main.tsx | 10 - .../runtime-compat/app-18/src/vite-env.d.ts | 1 - .../runtime-compat/app-18/tsconfig.app.json | 24 - .../app-18/tsconfig.app.tsbuildinfo | 1 - .../runtime-compat/app-18/tsconfig.json | 7 - .../runtime-compat/app-18/tsconfig.node.json | 22 - .../app-18/tsconfig.node.tsbuildinfo | 1 - .../runtime-compat/app-18/vite.config.ts | 11 - .../fixtures/runtime-compat/app-18/yarn.lock | 1682 ------------- .../fixtures/runtime-compat/app-19/.gitignore | 24 - .../fixtures/runtime-compat/app-19/README.md | 50 - .../runtime-compat/app-19/eslint.config.js | 28 - .../fixtures/runtime-compat/app-19/index.html | 13 - .../runtime-compat/app-19/package.json | 31 - .../runtime-compat/app-19/public/vite.svg | 1 - .../runtime-compat/app-19/src/App.css | 42 - .../runtime-compat/app-19/src/App.tsx | 16 - .../app-19/src/assets/react.svg | 1 - .../runtime-compat/app-19/src/index.css | 68 - .../runtime-compat/app-19/src/main.tsx | 10 - .../runtime-compat/app-19/src/vite-env.d.ts | 1 - .../runtime-compat/app-19/tsconfig.app.json | 24 - .../app-19/tsconfig.app.tsbuildinfo | 1 - .../runtime-compat/app-19/tsconfig.json | 7 - .../runtime-compat/app-19/tsconfig.node.json | 22 - .../app-19/tsconfig.node.tsbuildinfo | 1 - .../runtime-compat/app-19/vite.config.ts | 11 - .../fixtures/runtime-compat/app-19/yarn.lock | 1677 ------------- .../runtime-compat/lib/babel.config.js | 10 - compiler/fixtures/runtime-compat/lib/index.js | 13 - .../fixtures/runtime-compat/lib/package.json | 32 - .../runtime-compat/lib/rollup.config.js | 51 - .../fixtures/runtime-compat/lib/yarn.lock | 2215 ----------------- compiler/fixtures/runtime-compat/setup.sh | 13 - 46 files changed, 6397 deletions(-) create mode 100644 compiler/fixtures/.gitkeep delete mode 100644 compiler/fixtures/runtime-compat/README.md delete mode 100644 compiler/fixtures/runtime-compat/app-18/.gitignore delete mode 100644 compiler/fixtures/runtime-compat/app-18/README.md delete mode 100644 compiler/fixtures/runtime-compat/app-18/eslint.config.js delete mode 100644 compiler/fixtures/runtime-compat/app-18/index.html delete mode 100644 compiler/fixtures/runtime-compat/app-18/package.json delete mode 100644 compiler/fixtures/runtime-compat/app-18/public/vite.svg delete mode 100644 compiler/fixtures/runtime-compat/app-18/src/App.css delete mode 100644 compiler/fixtures/runtime-compat/app-18/src/App.tsx delete mode 100644 compiler/fixtures/runtime-compat/app-18/src/assets/react.svg delete mode 100644 compiler/fixtures/runtime-compat/app-18/src/index.css delete mode 100644 compiler/fixtures/runtime-compat/app-18/src/main.tsx delete mode 100644 compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts delete mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.app.json delete mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo delete mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.json delete mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.node.json delete mode 100644 compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo delete mode 100644 compiler/fixtures/runtime-compat/app-18/vite.config.ts delete mode 100644 compiler/fixtures/runtime-compat/app-18/yarn.lock delete mode 100644 compiler/fixtures/runtime-compat/app-19/.gitignore delete mode 100644 compiler/fixtures/runtime-compat/app-19/README.md delete mode 100644 compiler/fixtures/runtime-compat/app-19/eslint.config.js delete mode 100644 compiler/fixtures/runtime-compat/app-19/index.html delete mode 100644 compiler/fixtures/runtime-compat/app-19/package.json delete mode 100644 compiler/fixtures/runtime-compat/app-19/public/vite.svg delete mode 100644 compiler/fixtures/runtime-compat/app-19/src/App.css delete mode 100644 compiler/fixtures/runtime-compat/app-19/src/App.tsx delete mode 100644 compiler/fixtures/runtime-compat/app-19/src/assets/react.svg delete mode 100644 compiler/fixtures/runtime-compat/app-19/src/index.css delete mode 100644 compiler/fixtures/runtime-compat/app-19/src/main.tsx delete mode 100644 compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts delete mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.app.json delete mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo delete mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.json delete mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.node.json delete mode 100644 compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo delete mode 100644 compiler/fixtures/runtime-compat/app-19/vite.config.ts delete mode 100644 compiler/fixtures/runtime-compat/app-19/yarn.lock delete mode 100644 compiler/fixtures/runtime-compat/lib/babel.config.js delete mode 100644 compiler/fixtures/runtime-compat/lib/index.js delete mode 100644 compiler/fixtures/runtime-compat/lib/package.json delete mode 100644 compiler/fixtures/runtime-compat/lib/rollup.config.js delete mode 100644 compiler/fixtures/runtime-compat/lib/yarn.lock delete mode 100755 compiler/fixtures/runtime-compat/setup.sh diff --git a/compiler/fixtures/.gitkeep b/compiler/fixtures/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/compiler/fixtures/runtime-compat/README.md b/compiler/fixtures/runtime-compat/README.md deleted file mode 100644 index fea4018dfcd55..0000000000000 --- a/compiler/fixtures/runtime-compat/README.md +++ /dev/null @@ -1 +0,0 @@ -Reference library compiled with React Compiler. diff --git a/compiler/fixtures/runtime-compat/app-18/.gitignore b/compiler/fixtures/runtime-compat/app-18/.gitignore deleted file mode 100644 index a547bf36d8d11..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/compiler/fixtures/runtime-compat/app-18/README.md b/compiler/fixtures/runtime-compat/app-18/README.md deleted file mode 100644 index 74872fd4af60f..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: - -- Configure the top-level `parserOptions` property like this: - -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) -``` - -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from 'eslint-plugin-react' - -export default tseslint.config({ - // Set the react version - settings: { react: { version: '18.3' } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs['jsx-runtime'].rules, - }, -}) -``` diff --git a/compiler/fixtures/runtime-compat/app-18/eslint.config.js b/compiler/fixtures/runtime-compat/app-18/eslint.config.js deleted file mode 100644 index c6d2eb5006ea4..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/eslint.config.js +++ /dev/null @@ -1,28 +0,0 @@ -import js from '@eslint/js'; -import globals from 'globals'; -import reactHooks from 'eslint-plugin-react-hooks'; -import reactRefresh from 'eslint-plugin-react-refresh'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config( - {ignores: ['dist']}, - { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ['**/*.{ts,tsx}'], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - 'react-refresh/only-export-components': [ - 'warn', - {allowConstantExport: true}, - ], - }, - } -); diff --git a/compiler/fixtures/runtime-compat/app-18/index.html b/compiler/fixtures/runtime-compat/app-18/index.html deleted file mode 100644 index e4b78eae12304..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + React + TS - - -
- - - diff --git a/compiler/fixtures/runtime-compat/app-18/package.json b/compiler/fixtures/runtime-compat/app-18/package.json deleted file mode 100644 index cccdd5e176172..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "app-18", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "react": "^18.3.1", - "react-compiler-runtime": "19.0.0-beta-9ee70a1-20241017", - "react-dom": "^18.3.1", - "runtime-compat-lib": "file:../lib" - }, - "devDependencies": { - "@eslint/js": "^9.11.1", - "@types/react": "^18.3.10", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.2", - "babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017", - "eslint": "^9.11.1", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.12", - "globals": "^15.9.0", - "typescript": "^5.5.3", - "typescript-eslint": "^8.7.0", - "vite": "^5.4.8" - } -} diff --git a/compiler/fixtures/runtime-compat/app-18/public/vite.svg b/compiler/fixtures/runtime-compat/app-18/public/vite.svg deleted file mode 100644 index e7b8dfb1b2a60..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/src/App.css b/compiler/fixtures/runtime-compat/app-18/src/App.css deleted file mode 100644 index b9d355df2a595..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/compiler/fixtures/runtime-compat/app-18/src/App.tsx b/compiler/fixtures/runtime-compat/app-18/src/App.tsx deleted file mode 100644 index e9833294f9195..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/src/App.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import 'react'; -import './App.css'; -// @ts-expect-error no types -import {useTime} from 'runtime-compat-lib'; - -function App() { - const time = useTime(); - return ( - <> -

React 18

- Current time: {time.toLocaleString()} - - ); -} - -export default App; diff --git a/compiler/fixtures/runtime-compat/app-18/src/assets/react.svg b/compiler/fixtures/runtime-compat/app-18/src/assets/react.svg deleted file mode 100644 index 6c87de9bb3358..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/src/index.css b/compiler/fixtures/runtime-compat/app-18/src/index.css deleted file mode 100644 index 6119ad9a8faaa..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/src/index.css +++ /dev/null @@ -1,68 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/compiler/fixtures/runtime-compat/app-18/src/main.tsx b/compiler/fixtures/runtime-compat/app-18/src/main.tsx deleted file mode 100644 index 080dac371e6d8..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import {StrictMode} from 'react'; -import {createRoot} from 'react-dom/client'; -import App from './App.tsx'; -import './index.css'; - -createRoot(document.getElementById('root')!).render( - - - , -); diff --git a/compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts b/compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a0061..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.app.json b/compiler/fixtures/runtime-compat/app-18/tsconfig.app.json deleted file mode 100644 index f0a235055d246..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/tsconfig.app.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo b/compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo deleted file mode 100644 index fd34676dd9562..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/tsconfig.app.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.json b/compiler/fixtures/runtime-compat/app-18/tsconfig.json deleted file mode 100644 index 1ffef600d959e..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.node.json b/compiler/fixtures/runtime-compat/app-18/tsconfig.node.json deleted file mode 100644 index 0d3d71446a455..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/tsconfig.node.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] -} diff --git a/compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo b/compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo deleted file mode 100644 index 75ea0011dff53..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/tsconfig.node.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./vite.config.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-18/vite.config.ts b/compiler/fixtures/runtime-compat/app-18/vite.config.ts deleted file mode 100644 index dc514a333f215..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/vite.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {defineConfig} from 'vite'; -import react from '@vitejs/plugin-react'; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - react({ - babel: {plugins: [['babel-plugin-react-compiler', {target: '18'}]]}, - }), - ], -}); diff --git a/compiler/fixtures/runtime-compat/app-18/yarn.lock b/compiler/fixtures/runtime-compat/app-18/yarn.lock deleted file mode 100644 index aeaa712ae6bdf..0000000000000 --- a/compiler/fixtures/runtime-compat/app-18/yarn.lock +++ /dev/null @@ -1,1682 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" - integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== - dependencies: - "@babel/highlight" "^7.25.7" - picocolors "^1.0.0" - -"@babel/compat-data@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" - integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== - -"@babel/core@^7.25.2": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" - integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.25.7" - "@babel/generator" "^7.25.7" - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helpers" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/template" "^7.25.7" - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" - integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== - dependencies: - "@babel/types" "^7.2.0" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" - integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== - dependencies: - "@babel/types" "^7.25.7" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-compilation-targets@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" - integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== - dependencies: - "@babel/compat-data" "^7.25.7" - "@babel/helper-validator-option" "^7.25.7" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-module-imports@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" - integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-module-transforms@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" - integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== - dependencies: - "@babel/helper-module-imports" "^7.25.7" - "@babel/helper-simple-access" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/helper-plugin-utils@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" - integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== - -"@babel/helper-simple-access@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" - integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-string-parser@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" - integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== - -"@babel/helper-validator-identifier@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" - integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== - -"@babel/helper-validator-option@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" - integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== - -"@babel/helpers@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" - integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== - dependencies: - "@babel/template" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/highlight@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" - integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== - dependencies: - "@babel/helper-validator-identifier" "^7.25.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" - integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== - dependencies: - "@babel/types" "^7.25.7" - -"@babel/plugin-transform-react-jsx-self@^7.24.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz#3d11df143131fd8f5486a1f7d3839890f88f8c85" - integrity sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-react-jsx-source@^7.24.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz#a0d8372310d5ea5b0447dfa03a8485f960eff7be" - integrity sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/template@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" - integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== - dependencies: - "@babel/code-frame" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/traverse@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" - integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== - dependencies: - "@babel/code-frame" "^7.25.7" - "@babel/generator" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/template" "^7.25.7" - "@babel/types" "^7.25.7" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" - integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== - dependencies: - "@babel/helper-string-parser" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - to-fast-properties "^2.0.0" - -"@esbuild/aix-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" - integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== - -"@esbuild/android-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" - integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== - -"@esbuild/android-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" - integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== - -"@esbuild/android-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" - integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== - -"@esbuild/darwin-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== - -"@esbuild/darwin-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" - integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== - -"@esbuild/freebsd-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" - integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== - -"@esbuild/freebsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" - integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== - -"@esbuild/linux-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" - integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== - -"@esbuild/linux-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" - integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== - -"@esbuild/linux-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" - integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== - -"@esbuild/linux-loong64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" - integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== - -"@esbuild/linux-mips64el@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" - integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== - -"@esbuild/linux-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" - integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== - -"@esbuild/linux-riscv64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" - integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== - -"@esbuild/linux-s390x@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" - integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== - -"@esbuild/linux-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" - integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== - -"@esbuild/netbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" - integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== - -"@esbuild/openbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" - integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== - -"@esbuild/sunos-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" - integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== - -"@esbuild/win32-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" - integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== - -"@esbuild/win32-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" - integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== - -"@esbuild/win32-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" - integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== - -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" - integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== - -"@eslint/config-array@^0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" - integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== - dependencies: - "@eslint/object-schema" "^2.1.4" - debug "^4.3.1" - minimatch "^3.1.2" - -"@eslint/core@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" - integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== - -"@eslint/eslintrc@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" - integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^10.0.1" - globals "^14.0.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@9.12.0", "@eslint/js@^9.11.1": - version "9.12.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" - integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== - -"@eslint/object-schema@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" - integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== - -"@eslint/plugin-kit@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" - integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== - dependencies: - levn "^0.4.1" - -"@humanfs/core@^0.19.0": - version "0.19.0" - resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" - integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== - -"@humanfs/node@^0.16.5": - version "0.16.5" - resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" - integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== - dependencies: - "@humanfs/core" "^0.19.0" - "@humanwhocodes/retry" "^0.3.0" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" - integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== - -"@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@rollup/rollup-android-arm-eabi@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" - integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== - -"@rollup/rollup-android-arm64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" - integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== - -"@rollup/rollup-darwin-arm64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" - integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== - -"@rollup/rollup-darwin-x64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" - integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== - -"@rollup/rollup-linux-arm-gnueabihf@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" - integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== - -"@rollup/rollup-linux-arm-musleabihf@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" - integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== - -"@rollup/rollup-linux-arm64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" - integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== - -"@rollup/rollup-linux-arm64-musl@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" - integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" - integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== - -"@rollup/rollup-linux-riscv64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" - integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== - -"@rollup/rollup-linux-s390x-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" - integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== - -"@rollup/rollup-linux-x64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" - integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== - -"@rollup/rollup-linux-x64-musl@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" - integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== - -"@rollup/rollup-win32-arm64-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" - integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== - -"@rollup/rollup-win32-ia32-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" - integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== - -"@rollup/rollup-win32-x64-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" - integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== - -"@types/babel__core@^7.20.5": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" - integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" - integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" - integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== - dependencies: - "@babel/types" "^7.20.7" - -"@types/estree@1.0.6", "@types/estree@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" - integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" - integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== - -"@types/istanbul-lib-report@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" - integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - -"@types/json-schema@^7.0.15": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/prop-types@*": - version "15.7.13" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" - integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== - -"@types/react-dom@^18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@^18.3.10": - version "18.3.11" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.11.tgz#9d530601ff843ee0d7030d4227ea4360236bd537" - integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^13.0.0": - version "13.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" - integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" - integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== - dependencies: - "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.8.1" - "@typescript-eslint/type-utils" "8.8.1" - "@typescript-eslint/utils" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - graphemer "^1.4.0" - ignore "^5.3.1" - natural-compare "^1.4.0" - ts-api-utils "^1.3.0" - -"@typescript-eslint/parser@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" - integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== - dependencies: - "@typescript-eslint/scope-manager" "8.8.1" - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/typescript-estree" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" - integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== - dependencies: - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - -"@typescript-eslint/type-utils@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" - integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== - dependencies: - "@typescript-eslint/typescript-estree" "8.8.1" - "@typescript-eslint/utils" "8.8.1" - debug "^4.3.4" - ts-api-utils "^1.3.0" - -"@typescript-eslint/types@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" - integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== - -"@typescript-eslint/typescript-estree@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" - integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== - dependencies: - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - debug "^4.3.4" - fast-glob "^3.3.2" - is-glob "^4.0.3" - minimatch "^9.0.4" - semver "^7.6.0" - ts-api-utils "^1.3.0" - -"@typescript-eslint/utils@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" - integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.8.1" - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/typescript-estree" "8.8.1" - -"@typescript-eslint/visitor-keys@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" - integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== - dependencies: - "@typescript-eslint/types" "8.8.1" - eslint-visitor-keys "^3.4.3" - -"@vitejs/plugin-react@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz#1e13f666fe3135b477220d3c13b783704636b6e4" - integrity sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg== - dependencies: - "@babel/core" "^7.25.2" - "@babel/plugin-transform-react-jsx-self" "^7.24.7" - "@babel/plugin-transform-react-jsx-source" "^7.24.7" - "@types/babel__core" "^7.20.5" - react-refresh "^0.14.2" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^8.12.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -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== - -babel-plugin-react-compiler@19.0.0-beta-9ee70a1-20241017: - version "19.0.0-beta-9ee70a1-20241017" - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-9ee70a1-20241017.tgz#734036661d70e0d91c5f64414b31220ecc0019d2" - integrity sha512-AkSce5YYHcreFtuvzI9xnP2kwoYkub8Go3yrz7cPbbCE6oIhFxESbPWJVgye7yZckXuzEZYO4JSE8tq/U0oVfA== - dependencies: - "@babel/generator" "7.2.0" - "@babel/types" "^7.19.0" - chalk "4" - invariant "^2.2.4" - pretty-format "^24" - zod "^3.22.4" - zod-validation-error "^2.1.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.24.0: - version "4.24.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" - integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== - dependencies: - caniuse-lite "^1.0.30001663" - electron-to-chromium "^1.5.28" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" - -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.30001663: - version "1.0.30001667" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" - integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== - -chalk@4, chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -convert-source-map@^2.0.0: - version "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== - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -electron-to-chromium@^1.5.28: - version "1.5.35" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" - integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== - -esbuild@^0.21.3: - version "0.21.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" - integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== - optionalDependencies: - "@esbuild/aix-ppc64" "0.21.5" - "@esbuild/android-arm" "0.21.5" - "@esbuild/android-arm64" "0.21.5" - "@esbuild/android-x64" "0.21.5" - "@esbuild/darwin-arm64" "0.21.5" - "@esbuild/darwin-x64" "0.21.5" - "@esbuild/freebsd-arm64" "0.21.5" - "@esbuild/freebsd-x64" "0.21.5" - "@esbuild/linux-arm" "0.21.5" - "@esbuild/linux-arm64" "0.21.5" - "@esbuild/linux-ia32" "0.21.5" - "@esbuild/linux-loong64" "0.21.5" - "@esbuild/linux-mips64el" "0.21.5" - "@esbuild/linux-ppc64" "0.21.5" - "@esbuild/linux-riscv64" "0.21.5" - "@esbuild/linux-s390x" "0.21.5" - "@esbuild/linux-x64" "0.21.5" - "@esbuild/netbsd-x64" "0.21.5" - "@esbuild/openbsd-x64" "0.21.5" - "@esbuild/sunos-x64" "0.21.5" - "@esbuild/win32-arm64" "0.21.5" - "@esbuild/win32-ia32" "0.21.5" - "@esbuild/win32-x64" "0.21.5" - -escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-plugin-react-hooks@^5.1.0-rc.0: - version "5.1.0-rc-fb9a90fa48-20240614" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz#206a7ec005f0b286aaf7091f4e566083d310b189" - integrity sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w== - -eslint-plugin-react-refresh@^0.4.12: - version "0.4.12" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz#73d61c7fcbe3f7280edb6579380b4350d2f547ed" - integrity sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg== - -eslint-scope@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" - integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint-visitor-keys@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" - integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== - -eslint@^9.11.1: - version "9.12.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" - integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.11.0" - "@eslint/config-array" "^0.18.0" - "@eslint/core" "^0.6.0" - "@eslint/eslintrc" "^3.1.0" - "@eslint/js" "9.12.0" - "@eslint/plugin-kit" "^0.2.0" - "@humanfs/node" "^0.16.5" - "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.3.1" - "@types/estree" "^1.0.6" - "@types/json-schema" "^7.0.15" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - escape-string-regexp "^4.0.0" - eslint-scope "^8.1.0" - eslint-visitor-keys "^4.1.0" - espree "^10.2.0" - esquery "^1.5.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^8.0.0" - find-up "^5.0.0" - glob-parent "^6.0.2" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - json-stable-stringify-without-jsonify "^1.0.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - text-table "^0.2.0" - -espree@^10.0.1, espree@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" - integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== - dependencies: - acorn "^8.12.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^4.1.0" - -esquery@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" - integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" - integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== - dependencies: - flat-cache "^4.0.0" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" - integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.4" - -flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== - -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== - -globals@^15.9.0: - version "15.11.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e" - integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw== - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -ignore@^5.2.0, ignore@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -import-fresh@^3.2.1: - 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" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -"js-tokens@^3.0.0 || ^4.0.0", 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@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -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== - -keyv@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash@^4.17.10: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.0.0, loose-envify@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -ms@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== - -optionator@^0.9.3: - version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.5" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -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" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -picocolors@^1.0.0, picocolors@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -postcss@^8.4.43: - version "8.4.47" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" - integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== - dependencies: - nanoid "^3.3.7" - picocolors "^1.1.0" - source-map-js "^1.2.1" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -pretty-format@^24: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -react-compiler-runtime@19.0.0-beta-9ee70a1-20241017: - version "19.0.0-beta-9ee70a1-20241017" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-9ee70a1-20241017.tgz#ca35ba4ec80f2412fcdbfb911831308670acc13a" - integrity sha512-hVrlYbVacwEdZi08RUxSwIzZR2/+WxUsWRa7mjViRhqcqUYK+7u8UEVZoJrF5/gsCHMU9PhJRvolygSCaaE0nA== - -react-dom@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== - dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" - -react-is@^16.8.4: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-refresh@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" - integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== - -react@^18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" - -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== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rollup@^4.20.0: - version "4.24.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" - integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== - dependencies: - "@types/estree" "1.0.6" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.24.0" - "@rollup/rollup-android-arm64" "4.24.0" - "@rollup/rollup-darwin-arm64" "4.24.0" - "@rollup/rollup-darwin-x64" "4.24.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" - "@rollup/rollup-linux-arm-musleabihf" "4.24.0" - "@rollup/rollup-linux-arm64-gnu" "4.24.0" - "@rollup/rollup-linux-arm64-musl" "4.24.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" - "@rollup/rollup-linux-riscv64-gnu" "4.24.0" - "@rollup/rollup-linux-s390x-gnu" "4.24.0" - "@rollup/rollup-linux-x64-gnu" "4.24.0" - "@rollup/rollup-linux-x64-musl" "4.24.0" - "@rollup/rollup-win32-arm64-msvc" "4.24.0" - "@rollup/rollup-win32-ia32-msvc" "4.24.0" - "@rollup/rollup-win32-x64-msvc" "4.24.0" - fsevents "~2.3.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -"runtime-compat-lib@file:../lib": - version "0.0.0" - dependencies: - react-compiler-runtime "19.0.0-beta-9ee70a1-20241017" - -scheduler@^0.23.2: - version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" - integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== - dependencies: - loose-envify "^1.1.0" - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.6.0: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -source-map-js@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" - integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - -ts-api-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" - integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -typescript-eslint@^8.7.0: - version "8.8.1" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a" - integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ== - dependencies: - "@typescript-eslint/eslint-plugin" "8.8.1" - "@typescript-eslint/parser" "8.8.1" - "@typescript-eslint/utils" "8.8.1" - -typescript@^5.5.3: - version "5.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" - integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== - -update-browserslist-db@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" - integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -vite@^5.4.8: - version "5.4.8" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8" - integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ== - dependencies: - esbuild "^0.21.3" - postcss "^8.4.43" - rollup "^4.20.0" - optionalDependencies: - fsevents "~2.3.3" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zod-validation-error@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-2.1.0.tgz#208eac75237dfed47c0018d2fe8fd03501bfc9ac" - integrity sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ== - -zod@^3.22.4: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== diff --git a/compiler/fixtures/runtime-compat/app-19/.gitignore b/compiler/fixtures/runtime-compat/app-19/.gitignore deleted file mode 100644 index a547bf36d8d11..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/compiler/fixtures/runtime-compat/app-19/README.md b/compiler/fixtures/runtime-compat/app-19/README.md deleted file mode 100644 index 74872fd4af60f..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: - -- Configure the top-level `parserOptions` property like this: - -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) -``` - -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from 'eslint-plugin-react' - -export default tseslint.config({ - // Set the react version - settings: { react: { version: '18.3' } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs['jsx-runtime'].rules, - }, -}) -``` diff --git a/compiler/fixtures/runtime-compat/app-19/eslint.config.js b/compiler/fixtures/runtime-compat/app-19/eslint.config.js deleted file mode 100644 index c6d2eb5006ea4..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/eslint.config.js +++ /dev/null @@ -1,28 +0,0 @@ -import js from '@eslint/js'; -import globals from 'globals'; -import reactHooks from 'eslint-plugin-react-hooks'; -import reactRefresh from 'eslint-plugin-react-refresh'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config( - {ignores: ['dist']}, - { - extends: [js.configs.recommended, ...tseslint.configs.recommended], - files: ['**/*.{ts,tsx}'], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - }, - plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - 'react-refresh/only-export-components': [ - 'warn', - {allowConstantExport: true}, - ], - }, - } -); diff --git a/compiler/fixtures/runtime-compat/app-19/index.html b/compiler/fixtures/runtime-compat/app-19/index.html deleted file mode 100644 index e4b78eae12304..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + React + TS - - -
- - - diff --git a/compiler/fixtures/runtime-compat/app-19/package.json b/compiler/fixtures/runtime-compat/app-19/package.json deleted file mode 100644 index 3e92952c9de47..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "app-19", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "react": "19.0.0-beta-26f2496093-20240514", - "react-dom": "19.0.0-beta-26f2496093-20240514", - "runtime-compat-lib": "file:../lib" - }, - "devDependencies": { - "@eslint/js": "^9.11.1", - "@types/react": "^18.3.10", - "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.2", - "babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017", - "eslint": "^9.11.1", - "eslint-plugin-react-hooks": "^5.1.0-rc.0", - "eslint-plugin-react-refresh": "^0.4.12", - "globals": "^15.9.0", - "typescript": "^5.5.3", - "typescript-eslint": "^8.7.0", - "vite": "^5.4.8" - } -} diff --git a/compiler/fixtures/runtime-compat/app-19/public/vite.svg b/compiler/fixtures/runtime-compat/app-19/public/vite.svg deleted file mode 100644 index e7b8dfb1b2a60..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/src/App.css b/compiler/fixtures/runtime-compat/app-19/src/App.css deleted file mode 100644 index b9d355df2a595..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/compiler/fixtures/runtime-compat/app-19/src/App.tsx b/compiler/fixtures/runtime-compat/app-19/src/App.tsx deleted file mode 100644 index 35bafd4d2e681..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/src/App.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import 'react'; -import './App.css'; -// @ts-expect-error no types -import {useTime} from 'runtime-compat-lib'; - -function App() { - const time = useTime(); - return ( - <> -

React 19

- Current time: {time.toLocaleString()} - - ); -} - -export default App; diff --git a/compiler/fixtures/runtime-compat/app-19/src/assets/react.svg b/compiler/fixtures/runtime-compat/app-19/src/assets/react.svg deleted file mode 100644 index 6c87de9bb3358..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/src/index.css b/compiler/fixtures/runtime-compat/app-19/src/index.css deleted file mode 100644 index 6119ad9a8faaa..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/src/index.css +++ /dev/null @@ -1,68 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/compiler/fixtures/runtime-compat/app-19/src/main.tsx b/compiler/fixtures/runtime-compat/app-19/src/main.tsx deleted file mode 100644 index 080dac371e6d8..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import {StrictMode} from 'react'; -import {createRoot} from 'react-dom/client'; -import App from './App.tsx'; -import './index.css'; - -createRoot(document.getElementById('root')!).render( - - - , -); diff --git a/compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts b/compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2a0061..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.app.json b/compiler/fixtures/runtime-compat/app-19/tsconfig.app.json deleted file mode 100644 index f0a235055d246..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/tsconfig.app.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo b/compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo deleted file mode 100644 index fd34676dd9562..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/tsconfig.app.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./src/app.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.json b/compiler/fixtures/runtime-compat/app-19/tsconfig.json deleted file mode 100644 index 1ffef600d959e..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.node.json b/compiler/fixtures/runtime-compat/app-19/tsconfig.node.json deleted file mode 100644 index 0d3d71446a455..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/tsconfig.node.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] -} diff --git a/compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo b/compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo deleted file mode 100644 index 75ea0011dff53..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/tsconfig.node.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"root":["./vite.config.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/compiler/fixtures/runtime-compat/app-19/vite.config.ts b/compiler/fixtures/runtime-compat/app-19/vite.config.ts deleted file mode 100644 index b0ffa6441cda1..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/vite.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {defineConfig} from 'vite'; -import react from '@vitejs/plugin-react'; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [ - react({ - babel: {plugins: [['babel-plugin-react-compiler', {target: '19'}]]}, - }), - ], -}); diff --git a/compiler/fixtures/runtime-compat/app-19/yarn.lock b/compiler/fixtures/runtime-compat/app-19/yarn.lock deleted file mode 100644 index ddffd131007ce..0000000000000 --- a/compiler/fixtures/runtime-compat/app-19/yarn.lock +++ /dev/null @@ -1,1677 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/code-frame@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" - integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== - dependencies: - "@babel/highlight" "^7.25.7" - picocolors "^1.0.0" - -"@babel/compat-data@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" - integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== - -"@babel/core@^7.25.2": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" - integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.25.7" - "@babel/generator" "^7.25.7" - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helpers" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/template" "^7.25.7" - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" - integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== - dependencies: - "@babel/types" "^7.2.0" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" - integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== - dependencies: - "@babel/types" "^7.25.7" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-compilation-targets@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" - integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== - dependencies: - "@babel/compat-data" "^7.25.7" - "@babel/helper-validator-option" "^7.25.7" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-module-imports@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" - integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-module-transforms@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" - integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== - dependencies: - "@babel/helper-module-imports" "^7.25.7" - "@babel/helper-simple-access" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/helper-plugin-utils@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" - integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== - -"@babel/helper-simple-access@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" - integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-string-parser@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" - integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== - -"@babel/helper-validator-identifier@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" - integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== - -"@babel/helper-validator-option@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" - integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== - -"@babel/helpers@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" - integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== - dependencies: - "@babel/template" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/highlight@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" - integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== - dependencies: - "@babel/helper-validator-identifier" "^7.25.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" - integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== - dependencies: - "@babel/types" "^7.25.7" - -"@babel/plugin-transform-react-jsx-self@^7.24.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz#3d11df143131fd8f5486a1f7d3839890f88f8c85" - integrity sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-react-jsx-source@^7.24.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz#a0d8372310d5ea5b0447dfa03a8485f960eff7be" - integrity sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/template@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" - integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== - dependencies: - "@babel/code-frame" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/traverse@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" - integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== - dependencies: - "@babel/code-frame" "^7.25.7" - "@babel/generator" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/template" "^7.25.7" - "@babel/types" "^7.25.7" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.20.7", "@babel/types@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" - integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== - dependencies: - "@babel/helper-string-parser" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - to-fast-properties "^2.0.0" - -"@esbuild/aix-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" - integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== - -"@esbuild/android-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" - integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== - -"@esbuild/android-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" - integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== - -"@esbuild/android-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" - integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== - -"@esbuild/darwin-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== - -"@esbuild/darwin-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" - integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== - -"@esbuild/freebsd-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" - integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== - -"@esbuild/freebsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" - integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== - -"@esbuild/linux-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" - integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== - -"@esbuild/linux-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" - integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== - -"@esbuild/linux-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" - integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== - -"@esbuild/linux-loong64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" - integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== - -"@esbuild/linux-mips64el@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" - integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== - -"@esbuild/linux-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" - integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== - -"@esbuild/linux-riscv64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" - integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== - -"@esbuild/linux-s390x@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" - integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== - -"@esbuild/linux-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" - integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== - -"@esbuild/netbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" - integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== - -"@esbuild/openbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" - integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== - -"@esbuild/sunos-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" - integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== - -"@esbuild/win32-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" - integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== - -"@esbuild/win32-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" - integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== - -"@esbuild/win32-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" - integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== - -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" - integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== - -"@eslint/config-array@^0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" - integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== - dependencies: - "@eslint/object-schema" "^2.1.4" - debug "^4.3.1" - minimatch "^3.1.2" - -"@eslint/core@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" - integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== - -"@eslint/eslintrc@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" - integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^10.0.1" - globals "^14.0.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@9.12.0", "@eslint/js@^9.11.1": - version "9.12.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" - integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== - -"@eslint/object-schema@^2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" - integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== - -"@eslint/plugin-kit@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" - integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== - dependencies: - levn "^0.4.1" - -"@humanfs/core@^0.19.0": - version "0.19.0" - resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" - integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== - -"@humanfs/node@^0.16.5": - version "0.16.5" - resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" - integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== - dependencies: - "@humanfs/core" "^0.19.0" - "@humanwhocodes/retry" "^0.3.0" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" - integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== - -"@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@rollup/rollup-android-arm-eabi@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" - integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== - -"@rollup/rollup-android-arm64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" - integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== - -"@rollup/rollup-darwin-arm64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" - integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== - -"@rollup/rollup-darwin-x64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" - integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== - -"@rollup/rollup-linux-arm-gnueabihf@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" - integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== - -"@rollup/rollup-linux-arm-musleabihf@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" - integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== - -"@rollup/rollup-linux-arm64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" - integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== - -"@rollup/rollup-linux-arm64-musl@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" - integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" - integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== - -"@rollup/rollup-linux-riscv64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" - integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== - -"@rollup/rollup-linux-s390x-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" - integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== - -"@rollup/rollup-linux-x64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" - integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== - -"@rollup/rollup-linux-x64-musl@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" - integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== - -"@rollup/rollup-win32-arm64-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" - integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== - -"@rollup/rollup-win32-ia32-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" - integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== - -"@rollup/rollup-win32-x64-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" - integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== - -"@types/babel__core@^7.20.5": - version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" - integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== - dependencies: - "@babel/parser" "^7.20.7" - "@babel/types" "^7.20.7" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" - integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" - integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*": - version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" - integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== - dependencies: - "@babel/types" "^7.20.7" - -"@types/estree@1.0.6", "@types/estree@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" - integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" - integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== - -"@types/istanbul-lib-report@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" - integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - -"@types/json-schema@^7.0.15": - version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/prop-types@*": - version "15.7.13" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.13.tgz#2af91918ee12d9d32914feb13f5326658461b451" - integrity sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA== - -"@types/react-dom@^18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@^18.3.10": - version "18.3.11" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.11.tgz#9d530601ff843ee0d7030d4227ea4360236bd537" - integrity sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^13.0.0": - version "13.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" - integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" - integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== - dependencies: - "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.8.1" - "@typescript-eslint/type-utils" "8.8.1" - "@typescript-eslint/utils" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - graphemer "^1.4.0" - ignore "^5.3.1" - natural-compare "^1.4.0" - ts-api-utils "^1.3.0" - -"@typescript-eslint/parser@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" - integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== - dependencies: - "@typescript-eslint/scope-manager" "8.8.1" - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/typescript-estree" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" - integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== - dependencies: - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - -"@typescript-eslint/type-utils@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" - integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== - dependencies: - "@typescript-eslint/typescript-estree" "8.8.1" - "@typescript-eslint/utils" "8.8.1" - debug "^4.3.4" - ts-api-utils "^1.3.0" - -"@typescript-eslint/types@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" - integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== - -"@typescript-eslint/typescript-estree@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" - integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== - dependencies: - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/visitor-keys" "8.8.1" - debug "^4.3.4" - fast-glob "^3.3.2" - is-glob "^4.0.3" - minimatch "^9.0.4" - semver "^7.6.0" - ts-api-utils "^1.3.0" - -"@typescript-eslint/utils@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" - integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.8.1" - "@typescript-eslint/types" "8.8.1" - "@typescript-eslint/typescript-estree" "8.8.1" - -"@typescript-eslint/visitor-keys@8.8.1": - version "8.8.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" - integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== - dependencies: - "@typescript-eslint/types" "8.8.1" - eslint-visitor-keys "^3.4.3" - -"@vitejs/plugin-react@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz#1e13f666fe3135b477220d3c13b783704636b6e4" - integrity sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg== - dependencies: - "@babel/core" "^7.25.2" - "@babel/plugin-transform-react-jsx-self" "^7.24.7" - "@babel/plugin-transform-react-jsx-source" "^7.24.7" - "@types/babel__core" "^7.20.5" - react-refresh "^0.14.2" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^8.12.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-regex@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -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== - -babel-plugin-react-compiler@19.0.0-beta-9ee70a1-20241017: - version "19.0.0-beta-9ee70a1-20241017" - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-9ee70a1-20241017.tgz#734036661d70e0d91c5f64414b31220ecc0019d2" - integrity sha512-AkSce5YYHcreFtuvzI9xnP2kwoYkub8Go3yrz7cPbbCE6oIhFxESbPWJVgye7yZckXuzEZYO4JSE8tq/U0oVfA== - dependencies: - "@babel/generator" "7.2.0" - "@babel/types" "^7.19.0" - chalk "4" - invariant "^2.2.4" - pretty-format "^24" - zod "^3.22.4" - zod-validation-error "^2.1.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.24.0: - version "4.24.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" - integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== - dependencies: - caniuse-lite "^1.0.30001663" - electron-to-chromium "^1.5.28" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" - -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.30001663: - version "1.0.30001667" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" - integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== - -chalk@4, chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -convert-source-map@^2.0.0: - version "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== - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== - -debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -electron-to-chromium@^1.5.28: - version "1.5.35" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" - integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== - -esbuild@^0.21.3: - version "0.21.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" - integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== - optionalDependencies: - "@esbuild/aix-ppc64" "0.21.5" - "@esbuild/android-arm" "0.21.5" - "@esbuild/android-arm64" "0.21.5" - "@esbuild/android-x64" "0.21.5" - "@esbuild/darwin-arm64" "0.21.5" - "@esbuild/darwin-x64" "0.21.5" - "@esbuild/freebsd-arm64" "0.21.5" - "@esbuild/freebsd-x64" "0.21.5" - "@esbuild/linux-arm" "0.21.5" - "@esbuild/linux-arm64" "0.21.5" - "@esbuild/linux-ia32" "0.21.5" - "@esbuild/linux-loong64" "0.21.5" - "@esbuild/linux-mips64el" "0.21.5" - "@esbuild/linux-ppc64" "0.21.5" - "@esbuild/linux-riscv64" "0.21.5" - "@esbuild/linux-s390x" "0.21.5" - "@esbuild/linux-x64" "0.21.5" - "@esbuild/netbsd-x64" "0.21.5" - "@esbuild/openbsd-x64" "0.21.5" - "@esbuild/sunos-x64" "0.21.5" - "@esbuild/win32-arm64" "0.21.5" - "@esbuild/win32-ia32" "0.21.5" - "@esbuild/win32-x64" "0.21.5" - -escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-plugin-react-hooks@^5.1.0-rc.0: - version "5.1.0-rc-fb9a90fa48-20240614" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0-rc-fb9a90fa48-20240614.tgz#206a7ec005f0b286aaf7091f4e566083d310b189" - integrity sha512-xsiRwaDNF5wWNC4ZHLut+x/YcAxksUd9Rizt7LaEn3bV8VyYRpXnRJQlLOfYaVy9esk4DFP4zPPnoNVjq5Gc0w== - -eslint-plugin-react-refresh@^0.4.12: - version "0.4.12" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz#73d61c7fcbe3f7280edb6579380b4350d2f547ed" - integrity sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg== - -eslint-scope@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" - integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint-visitor-keys@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" - integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== - -eslint@^9.11.1: - version "9.12.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" - integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.11.0" - "@eslint/config-array" "^0.18.0" - "@eslint/core" "^0.6.0" - "@eslint/eslintrc" "^3.1.0" - "@eslint/js" "9.12.0" - "@eslint/plugin-kit" "^0.2.0" - "@humanfs/node" "^0.16.5" - "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.3.1" - "@types/estree" "^1.0.6" - "@types/json-schema" "^7.0.15" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - escape-string-regexp "^4.0.0" - eslint-scope "^8.1.0" - eslint-visitor-keys "^4.1.0" - espree "^10.2.0" - esquery "^1.5.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^8.0.0" - find-up "^5.0.0" - glob-parent "^6.0.2" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - json-stable-stringify-without-jsonify "^1.0.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - text-table "^0.2.0" - -espree@^10.0.1, espree@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" - integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== - dependencies: - acorn "^8.12.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^4.1.0" - -esquery@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" - integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" - integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== - dependencies: - flat-cache "^4.0.0" - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" - integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.4" - -flatted@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" - integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== - -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -glob-parent@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== - -globals@^15.9.0: - version "15.11.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e" - integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw== - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -ignore@^5.2.0, ignore@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -import-fresh@^3.2.1: - 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" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -"js-tokens@^3.0.0 || ^4.0.0", 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@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -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== - -keyv@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash@^4.17.10: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.8" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - -minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -ms@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== - -optionator@^0.9.3: - version "0.9.4" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.5" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -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" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -picocolors@^1.0.0, picocolors@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== - -picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -postcss@^8.4.43: - version "8.4.47" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" - integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== - dependencies: - nanoid "^3.3.7" - picocolors "^1.1.0" - source-map-js "^1.2.1" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -pretty-format@^24: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -react-compiler-runtime@19.0.0-beta-9ee70a1-20241017: - version "19.0.0-beta-9ee70a1-20241017" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-9ee70a1-20241017.tgz#ca35ba4ec80f2412fcdbfb911831308670acc13a" - integrity sha512-hVrlYbVacwEdZi08RUxSwIzZR2/+WxUsWRa7mjViRhqcqUYK+7u8UEVZoJrF5/gsCHMU9PhJRvolygSCaaE0nA== - -react-dom@19.0.0-beta-26f2496093-20240514: - version "19.0.0-beta-26f2496093-20240514" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-26f2496093-20240514.tgz#5fe4e829db8d379303057f539900a61ed6ca2615" - integrity sha512-UvQ+K1l3DFQ34LDgfFSNuUGi9EC+yfE9tS6MdpNTd5fx7qC7KLfepfC/KpxWMQZ7JfE3axD4ZO6H4cBSpAZpqw== - dependencies: - scheduler "0.25.0-beta-26f2496093-20240514" - -react-is@^16.8.4: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-refresh@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" - integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== - -react@19.0.0-beta-26f2496093-20240514: - version "19.0.0-beta-26f2496093-20240514" - resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-beta-26f2496093-20240514.tgz#3a0d63746b3f9ebd461a0731191bd08047fb1dbb" - integrity sha512-ZsU/WjNZ6GfzMWsq2DcGjElpV9it8JmETHm9mAJuOJNhuJcWJxt8ltCJabONFRpDFq1A/DP0d0KFj9CTJVM4VA== - -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== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rollup@^4.20.0: - version "4.24.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" - integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== - dependencies: - "@types/estree" "1.0.6" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.24.0" - "@rollup/rollup-android-arm64" "4.24.0" - "@rollup/rollup-darwin-arm64" "4.24.0" - "@rollup/rollup-darwin-x64" "4.24.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" - "@rollup/rollup-linux-arm-musleabihf" "4.24.0" - "@rollup/rollup-linux-arm64-gnu" "4.24.0" - "@rollup/rollup-linux-arm64-musl" "4.24.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" - "@rollup/rollup-linux-riscv64-gnu" "4.24.0" - "@rollup/rollup-linux-s390x-gnu" "4.24.0" - "@rollup/rollup-linux-x64-gnu" "4.24.0" - "@rollup/rollup-linux-x64-musl" "4.24.0" - "@rollup/rollup-win32-arm64-msvc" "4.24.0" - "@rollup/rollup-win32-ia32-msvc" "4.24.0" - "@rollup/rollup-win32-x64-msvc" "4.24.0" - fsevents "~2.3.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -"runtime-compat-lib@file:../lib": - version "0.0.0" - dependencies: - react-compiler-runtime "19.0.0-beta-9ee70a1-20241017" - -scheduler@0.25.0-beta-26f2496093-20240514: - version "0.25.0-beta-26f2496093-20240514" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-26f2496093-20240514.tgz#a3bc0ff694ec6de7a78c1e48e1f8f4a8555bd77d" - integrity sha512-vDwOytLHFnA3SW2B1lNcbO+/qKVyLCX+KLpm+tRGNDsXpyxzRgkIaYGWmX+S70AJGchUHCtuqQ50GFeFgDbXUw== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.6.0: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -source-map-js@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" - integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - -ts-api-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" - integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -typescript-eslint@^8.7.0: - version "8.8.1" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a" - integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ== - dependencies: - "@typescript-eslint/eslint-plugin" "8.8.1" - "@typescript-eslint/parser" "8.8.1" - "@typescript-eslint/utils" "8.8.1" - -typescript@^5.5.3: - version "5.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" - integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== - -update-browserslist-db@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" - integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -vite@^5.4.8: - version "5.4.8" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.8.tgz#af548ce1c211b2785478d3ba3e8da51e39a287e8" - integrity sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ== - dependencies: - esbuild "^0.21.3" - postcss "^8.4.43" - rollup "^4.20.0" - optionalDependencies: - fsevents "~2.3.3" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zod-validation-error@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-2.1.0.tgz#208eac75237dfed47c0018d2fe8fd03501bfc9ac" - integrity sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ== - -zod@^3.22.4: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== diff --git a/compiler/fixtures/runtime-compat/lib/babel.config.js b/compiler/fixtures/runtime-compat/lib/babel.config.js deleted file mode 100644 index 7c4be358783ba..0000000000000 --- a/compiler/fixtures/runtime-compat/lib/babel.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const plugins = [ - [ - 'babel-plugin-react-compiler', - { - target: '18', - }, - ], -]; - -module.exports = {plugins}; diff --git a/compiler/fixtures/runtime-compat/lib/index.js b/compiler/fixtures/runtime-compat/lib/index.js deleted file mode 100644 index 063ce1362d9f0..0000000000000 --- a/compiler/fixtures/runtime-compat/lib/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import {useState, useEffect} from 'react'; - -export function useTime() { - const [time, setTime] = useState(() => new Date()); - useEffect(() => { - const id = setInterval(() => { - setTime(new Date()); - }, 1000); - return () => clearInterval(id); - }, []); - - return time; -} diff --git a/compiler/fixtures/runtime-compat/lib/package.json b/compiler/fixtures/runtime-compat/lib/package.json deleted file mode 100644 index facfbb152a956..0000000000000 --- a/compiler/fixtures/runtime-compat/lib/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "runtime-compat-lib", - "version": "0.0.0", - "description": "Testing ground for libraries compiled with React Compiler", - "main": "dist/index.js", - "scripts": { - "build": "rimraf dist && rollup --config --bundleConfigAsCjs", - "test": "echo 'no tests'" - }, - "license": "MIT", - "devDependencies": { - "@babel/cli": "^7.25.7", - "@babel/core": "^7.25.7", - "@babel/preset-env": "^7.25.7", - "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-json": "^6.1.0", - "babel-plugin-react-compiler": "19.0.0-beta-9ee70a1-20241017", - "@rollup/plugin-terser": "^0.4.4", - "react": "19.0.0-beta-26f2496093-20240514", - "react-dom": "19.0.0-beta-26f2496093-20240514", - "rimraf": "5", - "rollup": "^4.22.4", - "rollup-plugin-banner2": "^1.2.3", - "rollup-plugin-prettier": "^4.1.1" - }, - "dependencies": { - "react-compiler-runtime": "19.0.0-beta-9ee70a1-20241017" - }, - "peerDependencies": { - "react": "^18 || ^19" - } -} diff --git a/compiler/fixtures/runtime-compat/lib/rollup.config.js b/compiler/fixtures/runtime-compat/lib/rollup.config.js deleted file mode 100644 index f5b2c221ed2f3..0000000000000 --- a/compiler/fixtures/runtime-compat/lib/rollup.config.js +++ /dev/null @@ -1,51 +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 json from '@rollup/plugin-json'; -import terser from '@rollup/plugin-terser'; -import prettier from 'rollup-plugin-prettier'; -import banner2 from 'rollup-plugin-banner2'; -import babel from '@rollup/plugin-babel'; - -const ROLLUP_CONFIG = { - input: 'index.js', - output: { - file: 'dist/index.js', - format: 'esm', - sourcemap: false, - exports: 'named', - }, - plugins: [ - json(), - babel({babelHelpers: 'bundled'}), - terser({ - format: { - comments: false, - }, - compress: false, - mangle: false, - }), - prettier(), - banner2( - () => `/** - * 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. - * - * @lightSyntaxTransform - * @noflow - * @nolint - * @preventMunge - * @preserve-invariant-messages - */ -` - ), - ], -}; - -export default ROLLUP_CONFIG; diff --git a/compiler/fixtures/runtime-compat/lib/yarn.lock b/compiler/fixtures/runtime-compat/lib/yarn.lock deleted file mode 100644 index 72cebdb2642a0..0000000000000 --- a/compiler/fixtures/runtime-compat/lib/yarn.lock +++ /dev/null @@ -1,2215 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.2.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" - integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@babel/cli@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.25.7.tgz#f76693c7cfb93c99844d3ed87ed4f291383ef1bf" - integrity sha512-vQw4QjrqjLSuL0Tt3gfVXbxEHOfsCcHN8tKyTclpSMYLq3Bp0BTzWYZfMKBs3PQ+to8q3BnumBIAsMdOqDJ6nw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.25" - commander "^6.2.0" - convert-source-map "^2.0.0" - fs-readdir-recursive "^1.1.0" - glob "^7.2.0" - make-dir "^2.1.0" - slash "^2.0.0" - optionalDependencies: - "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" - chokidar "^3.6.0" - -"@babel/code-frame@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" - integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== - dependencies: - "@babel/highlight" "^7.25.7" - picocolors "^1.0.0" - -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" - integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== - -"@babel/core@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" - integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.25.7" - "@babel/generator" "^7.25.7" - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helpers" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/template" "^7.25.7" - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/generator@7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.2.0.tgz#eaf3821fa0301d9d4aef88e63d4bcc19b73ba16c" - integrity sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg== - dependencies: - "@babel/types" "^7.2.0" - jsesc "^2.5.1" - lodash "^4.17.10" - source-map "^0.5.0" - trim-right "^1.0.1" - -"@babel/generator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" - integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== - dependencies: - "@babel/types" "^7.25.7" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^3.0.2" - -"@babel/helper-annotate-as-pure@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz#63f02dbfa1f7cb75a9bdb832f300582f30bb8972" - integrity sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA== - dependencies: - "@babel/types" "^7.25.7" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz#d721650c1f595371e0a23ee816f1c3c488c0d622" - integrity sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" - integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== - dependencies: - "@babel/compat-data" "^7.25.7" - "@babel/helper-validator-option" "^7.25.7" - browserslist "^4.24.0" - lru-cache "^5.1.1" - semver "^6.3.1" - -"@babel/helper-create-class-features-plugin@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz#5d65074c76cae75607421c00d6bd517fe1892d6b" - integrity sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.7" - "@babel/helper-member-expression-to-functions" "^7.25.7" - "@babel/helper-optimise-call-expression" "^7.25.7" - "@babel/helper-replace-supers" "^7.25.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" - "@babel/traverse" "^7.25.7" - semver "^6.3.1" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz#dcb464f0e2cdfe0c25cc2a0a59c37ab940ce894e" - integrity sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.7" - regexpu-core "^6.1.1" - semver "^6.3.1" - -"@babel/helper-define-polyfill-provider@^0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" - integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== - dependencies: - "@babel/helper-compilation-targets" "^7.22.6" - "@babel/helper-plugin-utils" "^7.22.5" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - -"@babel/helper-member-expression-to-functions@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz#541a33b071f0355a63a0fa4bdf9ac360116b8574" - integrity sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-module-imports@^7.18.6", "@babel/helper-module-imports@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" - integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-module-transforms@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" - integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== - dependencies: - "@babel/helper-module-imports" "^7.25.7" - "@babel/helper-simple-access" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/helper-optimise-call-expression@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz#1de1b99688e987af723eed44fa7fc0ee7b97d77a" - integrity sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng== - dependencies: - "@babel/types" "^7.25.7" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" - integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== - -"@babel/helper-remap-async-to-generator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz#9efdc39df5f489bcd15533c912b6c723a0a65021" - integrity sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.7" - "@babel/helper-wrap-function" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/helper-replace-supers@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz#38cfda3b6e990879c71d08d0fef9236b62bd75f5" - integrity sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.25.7" - "@babel/helper-optimise-call-expression" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/helper-simple-access@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" - integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-skip-transparent-expression-wrappers@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz#382831c91038b1a6d32643f5f49505b8442cb87c" - integrity sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA== - dependencies: - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helper-string-parser@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" - integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== - -"@babel/helper-validator-identifier@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" - integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== - -"@babel/helper-validator-option@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" - integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== - -"@babel/helper-wrap-function@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz#9f6021dd1c4fdf4ad515c809967fc4bac9a70fe7" - integrity sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg== - dependencies: - "@babel/template" "^7.25.7" - "@babel/traverse" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/helpers@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" - integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== - dependencies: - "@babel/template" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/highlight@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" - integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== - dependencies: - "@babel/helper-validator-identifier" "^7.25.7" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" - -"@babel/parser@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" - integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== - dependencies: - "@babel/types" "^7.25.7" - -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz#93969ac50ef4d68b2504b01b758af714e4cbdd64" - integrity sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz#a338d611adb9dcd599b8b1efa200c88ebeffe046" - integrity sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz#c5f755e911dfac7ef6957300c0f9c4a8c18c06f4" - integrity sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz#3b7ea04492ded990978b6deaa1dfca120ad4455a" - integrity sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" - "@babel/plugin-transform-optional-chaining" "^7.25.7" - -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz#9622b1d597a703aa3a921e6f58c9c2d9a028d2c5" - integrity sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": - version "7.21.0-placeholder-for-preset-env.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" - integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-import-assertions@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz#8ce248f9f4ed4b7ed4cb2e0eb4ed9efd9f52921f" - integrity sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-syntax-import-attributes@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz#d78dd0499d30df19a598e63ab895e21b909bc43f" - integrity sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-syntax-import-meta@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" - integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-transform-arrow-functions@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz#1b9ed22e6890a0e9ff470371c73b8c749bcec386" - integrity sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-async-generator-functions@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.7.tgz#af61a02b30d7bff5108c63bd39ac7938403426d7" - integrity sha512-4B6OhTrwYKHYYgcwErvZjbmH9X5TxQBsaBHdzEIB4l71gR5jh/tuHGlb9in47udL2+wVUcOz5XXhhfhVJwEpEg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-remap-async-to-generator" "^7.25.7" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/traverse" "^7.25.7" - -"@babel/plugin-transform-async-to-generator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz#a44c7323f8d4285a6c568dd43c5c361d6367ec52" - integrity sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg== - dependencies: - "@babel/helper-module-imports" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-remap-async-to-generator" "^7.25.7" - -"@babel/plugin-transform-block-scoped-functions@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz#e0b8843d5571719a2f1bf7e284117a3379fcc17c" - integrity sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-block-scoping@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz#6dab95e98adf780ceef1b1c3ab0e55cd20dd410a" - integrity sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-class-properties@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz#a389cfca7a10ac80e3ff4c75fca08bd097ad1523" - integrity sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-class-static-block@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.7.tgz#d2cf3c812e3b3162d56aadf4566f45c30538cb2c" - integrity sha512-rvUUtoVlkDWtDWxGAiiQj0aNktTPn3eFynBcMC2IhsXweehwgdI9ODe+XjWw515kEmv22sSOTp/rxIRuTiB7zg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-transform-classes@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz#5103206cf80d02283bbbd044509ea3b65d0906bb" - integrity sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.7" - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-replace-supers" "^7.25.7" - "@babel/traverse" "^7.25.7" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz#7f621f0aa1354b5348a935ab12e3903842466f65" - integrity sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/template" "^7.25.7" - -"@babel/plugin-transform-destructuring@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz#f6f26a9feefb5aa41fd45b6f5838901b5333d560" - integrity sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-dotall-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz#9d775c4a3ff1aea64045300fcd4309b4a610ef02" - integrity sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-duplicate-keys@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz#fbba7d1155eab76bd4f2a038cbd5d65883bd7a93" - integrity sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz#102b31608dcc22c08fbca1894e104686029dc141" - integrity sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-dynamic-import@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.7.tgz#31905ab2cfa94dcf1b1f8ce66096720b2908e518" - integrity sha512-UvcLuual4h7/GfylKm2IAA3aph9rwvAM2XBA0uPKU3lca+Maai4jBjjEVUS568ld6kJcgbouuumCBhMd/Yz17w== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-transform-exponentiation-operator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz#5961a3a23a398faccd6cddb34a2182807d75fb5f" - integrity sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-export-namespace-from@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.7.tgz#beb2679db6fd3bdfe6ad6de2c8cac84a86ef2da1" - integrity sha512-h3MDAP5l34NQkkNulsTNyjdaR+OiB0Im67VU//sFupouP8Q6m9Spy7l66DcaAQxtmCqGdanPByLsnwFttxKISQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-transform-for-of@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz#0acfea0f27aa290818b5b48a5a44b3f03fc13669" - integrity sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" - -"@babel/plugin-transform-function-name@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz#7e394ccea3693902a8b50ded8b6ae1fa7b8519fd" - integrity sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ== - dependencies: - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/plugin-transform-json-strings@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.7.tgz#6626433554aff4bd6f76a2c621a1f40e802dfb0a" - integrity sha512-Ot43PrL9TEAiCe8C/2erAjXMeVSnE/BLEx6eyrKLNFCCw5jvhTHKyHxdI1pA0kz5njZRYAnMO2KObGqOCRDYSA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-transform-literals@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz#70cbdc742f2cfdb1a63ea2cbd018d12a60b213c3" - integrity sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-logical-assignment-operators@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.7.tgz#93847feb513a1f191c5f5d903d991a0ee24fe99b" - integrity sha512-iImzbA55BjiovLyG2bggWS+V+OLkaBorNvc/yJoeeDQGztknRnDdYfp2d/UPmunZYEnZi6Lg8QcTmNMHOB0lGA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-transform-member-expression-literals@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz#0a36c3fbd450cc9e6485c507f005fa3d1bc8fca5" - integrity sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-modules-amd@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz#bb4e543b5611f6c8c685a2fd485408713a3adf3d" - integrity sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA== - dependencies: - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-modules-commonjs@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz#173f0c791bb7407c092ce6d77ee90eb3f2d1d2fd" - integrity sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg== - dependencies: - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-simple-access" "^7.25.7" - -"@babel/plugin-transform-modules-systemjs@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz#8b14d319a177cc9c85ef8b0512afd429d9e2e60b" - integrity sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g== - dependencies: - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - "@babel/traverse" "^7.25.7" - -"@babel/plugin-transform-modules-umd@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz#00ee7a7e124289549381bfb0e24d87fd7f848367" - integrity sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw== - dependencies: - "@babel/helper-module-transforms" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz#a2f3f6d7f38693b462542951748f0a72a34d196d" - integrity sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-new-target@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz#52b2bde523b76c548749f38dc3054f1f45e82bc9" - integrity sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-nullish-coalescing-operator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.7.tgz#0af84b86d4332654c43cf028dbdcf878b00ac168" - integrity sha512-FbuJ63/4LEL32mIxrxwYaqjJxpbzxPVQj5a+Ebrc8JICV6YX8nE53jY+K0RZT3um56GoNWgkS2BQ/uLGTjtwfw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-transform-numeric-separator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.7.tgz#a516b78f894d1c08283f39d809b2048fd2f29448" - integrity sha512-8CbutzSSh4hmD+jJHIA8vdTNk15kAzOnFLVVgBSMGr28rt85ouT01/rezMecks9pkU939wDInImwCKv4ahU4IA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-transform-object-rest-spread@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.7.tgz#fa0916521be96fd434e2db59780b24b308c6d169" - integrity sha512-1JdVKPhD7Y5PvgfFy0Mv2brdrolzpzSoUq2pr6xsR+m+3viGGeHEokFKsCgOkbeFOQxfB1Vt2F0cPJLRpFI4Zg== - dependencies: - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.25.7" - -"@babel/plugin-transform-object-super@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz#582a9cea8cf0a1e02732be5b5a703a38dedf5661" - integrity sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-replace-supers" "^7.25.7" - -"@babel/plugin-transform-optional-catch-binding@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.7.tgz#400e2d891f9288f5231694234696aa67164e4913" - integrity sha512-m9obYBA39mDPN7lJzD5WkGGb0GO54PPLXsbcnj1Hyeu8mSRz7Gb4b1A6zxNX32ZuUySDK4G6it8SDFWD1nCnqg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-transform-optional-chaining@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.7.tgz#b7f7c9321aa1d8414e67799c28d87c23682e4d68" - integrity sha512-h39agClImgPWg4H8mYVAbD1qP9vClFbEjqoJmt87Zen8pjqK8FTPUwrOXAvqu5soytwxrLMd2fx2KSCp2CHcNg== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-transform-parameters@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz#80c38b03ef580f6d6bffe1c5254bb35986859ac7" - integrity sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-private-methods@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz#c790a04f837b4bd61d6b0317b43aa11ff67dce80" - integrity sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-private-property-in-object@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.7.tgz#aff877efd05b57c4ad04611d8de97bf155a53369" - integrity sha512-LzA5ESzBy7tqj00Yjey9yWfs3FKy4EmJyKOSWld144OxkTji81WWnUT8nkLUn+imN/zHL8ZQlOu/MTUAhHaX3g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.25.7" - "@babel/helper-create-class-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-transform-property-literals@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz#a8612b4ea4e10430f00012ecf0155662c7d6550d" - integrity sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-regenerator@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz#6eb006e6d26f627bc2f7844a9f19770721ad6f3e" - integrity sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - regenerator-transform "^0.15.2" - -"@babel/plugin-transform-reserved-words@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz#dc56b25e02afaabef3ce0c5b06b0916e8523e995" - integrity sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-shorthand-properties@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz#92690a9c671915602d91533c278cc8f6bf12275f" - integrity sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-spread@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz#df83e899a9fc66284ee601a7b738568435b92998" - integrity sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" - -"@babel/plugin-transform-sticky-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz#341c7002bef7f29037be7fb9684e374442dd0d17" - integrity sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-template-literals@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz#e566c581bb16d8541dd8701093bb3457adfce16b" - integrity sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-typeof-symbol@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz#debb1287182efd20488f126be343328c679b66eb" - integrity sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-unicode-escapes@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz#973592b6d13a914794e1de8cf1383e50e0f87f81" - integrity sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ== - dependencies: - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-unicode-property-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz#25349197cce964b1343f74fa7cfdf791a1b1919e" - integrity sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-unicode-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz#f93a93441baf61f713b6d5552aaa856bfab34809" - integrity sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/plugin-transform-unicode-sets-regex@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz#d1b3295d29e0f8f4df76abc909ad1ebee919560c" - integrity sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - -"@babel/preset-env@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.7.tgz#fc1b092152db4b58377b85dc05c890081c1157e0" - integrity sha512-Gibz4OUdyNqqLj+7OAvBZxOD7CklCtMA5/j0JgUEwOnaRULsPDXmic2iKxL2DX2vQduPR5wH2hjZas/Vr/Oc0g== - dependencies: - "@babel/compat-data" "^7.25.7" - "@babel/helper-compilation-targets" "^7.25.7" - "@babel/helper-plugin-utils" "^7.25.7" - "@babel/helper-validator-option" "^7.25.7" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.7" - "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.7" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.7" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.7" - "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.25.7" - "@babel/plugin-syntax-import-attributes" "^7.25.7" - "@babel/plugin-syntax-import-meta" "^7.10.4" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.25.7" - "@babel/plugin-transform-async-generator-functions" "^7.25.7" - "@babel/plugin-transform-async-to-generator" "^7.25.7" - "@babel/plugin-transform-block-scoped-functions" "^7.25.7" - "@babel/plugin-transform-block-scoping" "^7.25.7" - "@babel/plugin-transform-class-properties" "^7.25.7" - "@babel/plugin-transform-class-static-block" "^7.25.7" - "@babel/plugin-transform-classes" "^7.25.7" - "@babel/plugin-transform-computed-properties" "^7.25.7" - "@babel/plugin-transform-destructuring" "^7.25.7" - "@babel/plugin-transform-dotall-regex" "^7.25.7" - "@babel/plugin-transform-duplicate-keys" "^7.25.7" - "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.7" - "@babel/plugin-transform-dynamic-import" "^7.25.7" - "@babel/plugin-transform-exponentiation-operator" "^7.25.7" - "@babel/plugin-transform-export-namespace-from" "^7.25.7" - "@babel/plugin-transform-for-of" "^7.25.7" - "@babel/plugin-transform-function-name" "^7.25.7" - "@babel/plugin-transform-json-strings" "^7.25.7" - "@babel/plugin-transform-literals" "^7.25.7" - "@babel/plugin-transform-logical-assignment-operators" "^7.25.7" - "@babel/plugin-transform-member-expression-literals" "^7.25.7" - "@babel/plugin-transform-modules-amd" "^7.25.7" - "@babel/plugin-transform-modules-commonjs" "^7.25.7" - "@babel/plugin-transform-modules-systemjs" "^7.25.7" - "@babel/plugin-transform-modules-umd" "^7.25.7" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.7" - "@babel/plugin-transform-new-target" "^7.25.7" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.25.7" - "@babel/plugin-transform-numeric-separator" "^7.25.7" - "@babel/plugin-transform-object-rest-spread" "^7.25.7" - "@babel/plugin-transform-object-super" "^7.25.7" - "@babel/plugin-transform-optional-catch-binding" "^7.25.7" - "@babel/plugin-transform-optional-chaining" "^7.25.7" - "@babel/plugin-transform-parameters" "^7.25.7" - "@babel/plugin-transform-private-methods" "^7.25.7" - "@babel/plugin-transform-private-property-in-object" "^7.25.7" - "@babel/plugin-transform-property-literals" "^7.25.7" - "@babel/plugin-transform-regenerator" "^7.25.7" - "@babel/plugin-transform-reserved-words" "^7.25.7" - "@babel/plugin-transform-shorthand-properties" "^7.25.7" - "@babel/plugin-transform-spread" "^7.25.7" - "@babel/plugin-transform-sticky-regex" "^7.25.7" - "@babel/plugin-transform-template-literals" "^7.25.7" - "@babel/plugin-transform-typeof-symbol" "^7.25.7" - "@babel/plugin-transform-unicode-escapes" "^7.25.7" - "@babel/plugin-transform-unicode-property-regex" "^7.25.7" - "@babel/plugin-transform-unicode-regex" "^7.25.7" - "@babel/plugin-transform-unicode-sets-regex" "^7.25.7" - "@babel/preset-modules" "0.1.6-no-external-plugins" - babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.6" - babel-plugin-polyfill-regenerator "^0.6.1" - core-js-compat "^3.38.1" - semver "^6.3.1" - -"@babel/preset-modules@0.1.6-no-external-plugins": - version "0.1.6-no-external-plugins" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" - integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/runtime@^7.8.4": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6" - integrity sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/template@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" - integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== - dependencies: - "@babel/code-frame" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/types" "^7.25.7" - -"@babel/traverse@^7.25.7": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" - integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== - dependencies: - "@babel/code-frame" "^7.25.7" - "@babel/generator" "^7.25.7" - "@babel/parser" "^7.25.7" - "@babel/template" "^7.25.7" - "@babel/types" "^7.25.7" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.25.7", "@babel/types@^7.4.4": - version "7.25.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" - integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== - dependencies: - "@babel/helper-string-parser" "^7.25.7" - "@babel/helper-validator-identifier" "^7.25.7" - to-fast-properties "^2.0.0" - -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - -"@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" - integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== - dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/set-array@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" - integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== - -"@jridgewell/source-map@^0.3.3": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" - integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" - -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": - version "2.1.8-no-fsevents.3" - resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" - integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== - -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - -"@rollup/plugin-babel@^6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz#bd698e351fa9aa9619fcae780aea2a603d98e4c4" - integrity sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw== - dependencies: - "@babel/helper-module-imports" "^7.18.6" - "@rollup/pluginutils" "^5.0.1" - -"@rollup/plugin-json@^6.1.0": - version "6.1.0" - resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-6.1.0.tgz#fbe784e29682e9bb6dee28ea75a1a83702e7b805" - integrity sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA== - dependencies: - "@rollup/pluginutils" "^5.1.0" - -"@rollup/plugin-terser@^0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz#15dffdb3f73f121aa4fbb37e7ca6be9aeea91962" - integrity sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A== - dependencies: - serialize-javascript "^6.0.1" - smob "^1.0.0" - terser "^5.17.4" - -"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.2.tgz#d3bc9f0fea4fd4086aaac6aa102f3fa587ce8bd9" - integrity sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^2.0.2" - picomatch "^2.3.1" - -"@rollup/rollup-android-arm-eabi@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" - integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== - -"@rollup/rollup-android-arm64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" - integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== - -"@rollup/rollup-darwin-arm64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" - integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== - -"@rollup/rollup-darwin-x64@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" - integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== - -"@rollup/rollup-linux-arm-gnueabihf@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" - integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== - -"@rollup/rollup-linux-arm-musleabihf@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" - integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== - -"@rollup/rollup-linux-arm64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" - integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== - -"@rollup/rollup-linux-arm64-musl@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" - integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== - -"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" - integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== - -"@rollup/rollup-linux-riscv64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" - integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== - -"@rollup/rollup-linux-s390x-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" - integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== - -"@rollup/rollup-linux-x64-gnu@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" - integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== - -"@rollup/rollup-linux-x64-musl@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" - integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== - -"@rollup/rollup-win32-arm64-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" - integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== - -"@rollup/rollup-win32-ia32-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" - integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== - -"@rollup/rollup-win32-x64-msvc@4.24.0": - version "4.24.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" - integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== - -"@types/estree@1.0.6", "@types/estree@^1.0.0": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" - integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" - integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== - -"@types/istanbul-lib-report@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" - integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - -"@types/prettier@^1.0.0 || ^2.0.0 || ^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-3.0.0.tgz#e9bc8160230d3a461dab5c5b41cceef1ef723057" - integrity sha512-mFMBfMOz8QxhYVbuINtswBp9VL2b4Y0QqYHwqLz3YbgtfAcat2Dl6Y1o4e22S/OVE6Ebl9m7wWiMT2lSbAs1wA== - dependencies: - prettier "*" - -"@types/yargs-parser@*": - version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" - integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== - -"@types/yargs@^13.0.0": - version "13.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" - integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== - dependencies: - "@types/yargs-parser" "*" - -acorn@^8.8.2: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - -ansi-regex@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -babel-plugin-polyfill-corejs2@^0.4.10: - version "0.4.11" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" - integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== - dependencies: - "@babel/compat-data" "^7.22.6" - "@babel/helper-define-polyfill-provider" "^0.6.2" - semver "^6.3.1" - -babel-plugin-polyfill-corejs3@^0.10.6: - version "0.10.6" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" - integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.2" - core-js-compat "^3.38.0" - -babel-plugin-polyfill-regenerator@^0.6.1: - version "0.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" - integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.2" - -babel-plugin-react-compiler@19.0.0-beta-9ee70a1-20241017: - version "19.0.0-beta-9ee70a1-20241017" - resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-9ee70a1-20241017.tgz#734036661d70e0d91c5f64414b31220ecc0019d2" - integrity sha512-AkSce5YYHcreFtuvzI9xnP2kwoYkub8Go3yrz7cPbbCE6oIhFxESbPWJVgye7yZckXuzEZYO4JSE8tq/U0oVfA== - dependencies: - "@babel/generator" "7.2.0" - "@babel/types" "^7.19.0" - chalk "4" - invariant "^2.2.4" - pretty-format "^24" - zod "^3.22.4" - zod-validation-error "^2.1.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@~3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - -browserslist@^4.23.3, browserslist@^4.24.0: - version "4.24.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" - integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== - dependencies: - caniuse-lite "^1.0.30001663" - electron-to-chromium "^1.5.28" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -caniuse-lite@^1.0.30001663: - version "1.0.30001667" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" - integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== - -chalk@4: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chokidar@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -convert-source-map@^2.0.0: - version "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== - -core-js-compat@^3.38.0, core-js-compat@^3.38.1: - version "3.38.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09" - integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw== - dependencies: - browserslist "^4.23.3" - -cross-spawn@^7.0.0: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - -diff@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" - integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== - -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - -electron-to-chromium@^1.5.28: - version "1.5.35" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" - integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - -escalade@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -estree-walker@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - -foreground-child@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" - integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^4.0.1" - -fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^10.3.7: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - -glob@^7.2.0: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-core-module@^2.13.0: - version "2.15.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" - integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== - dependencies: - hasown "^2.0.2" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - -"js-tokens@^3.0.0 || ^4.0.0", 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== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@^3.0.2, jsesc@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - -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== - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - -lodash.hasin@4.5.2: - version "4.5.2" - resolved "https://registry.yarnpkg.com/lodash.hasin/-/lodash.hasin-4.5.2.tgz#f91e352378d21ef7090b9e7687c2ca35c5b4d52a" - integrity sha512-AFAitwTSq1Ka/1J9uBaVxpLBP5OI3INQvkl4wKcgIYxoA0S3aqO1QWXHR9aCcOrWtPFqP7GzlFncZfe0Jz0kNw== - -lodash.isempty@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" - integrity sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg== - -lodash.isnil@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c" - integrity sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng== - -lodash.omitby@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.omitby/-/lodash.omitby-4.6.0.tgz#5c15ff4754ad555016b53c041311e8f079204791" - integrity sha512-5OrRcIVR75M288p4nbI2WLAf3ndw2GD9fyNv3Bc15+WCxJDdZ4lYndSxGd7hnG6PVjiJTeJE2dHEGhIuKGicIQ== - -lodash@^4.17.10: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -magic-string@0.30.5: - version "0.30.5" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" - integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - -magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - dependencies: - sourcemap-codec "^1.4.8" - -make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - -minimatch@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== - dependencies: - brace-expansion "^2.0.1" - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - -ms@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -node-releases@^2.0.18: - version "2.0.18" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" - integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -package-json-from-dist@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" - integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - -picocolors@^1.0.0, picocolors@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - -prettier@*: - version "3.3.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" - integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== - -pretty-format@^24: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -react-compiler-runtime@19.0.0-beta-9ee70a1-20241017: - version "19.0.0-beta-9ee70a1-20241017" - resolved "https://registry.yarnpkg.com/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-9ee70a1-20241017.tgz#ca35ba4ec80f2412fcdbfb911831308670acc13a" - integrity sha512-hVrlYbVacwEdZi08RUxSwIzZR2/+WxUsWRa7mjViRhqcqUYK+7u8UEVZoJrF5/gsCHMU9PhJRvolygSCaaE0nA== - -react-dom@19.0.0-beta-26f2496093-20240514: - version "19.0.0-beta-26f2496093-20240514" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0-beta-26f2496093-20240514.tgz#5fe4e829db8d379303057f539900a61ed6ca2615" - integrity sha512-UvQ+K1l3DFQ34LDgfFSNuUGi9EC+yfE9tS6MdpNTd5fx7qC7KLfepfC/KpxWMQZ7JfE3axD4ZO6H4cBSpAZpqw== - dependencies: - scheduler "0.25.0-beta-26f2496093-20240514" - -react-is@^16.8.4: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react@19.0.0-beta-26f2496093-20240514: - version "19.0.0-beta-26f2496093-20240514" - resolved "https://registry.yarnpkg.com/react/-/react-19.0.0-beta-26f2496093-20240514.tgz#3a0d63746b3f9ebd461a0731191bd08047fb1dbb" - integrity sha512-ZsU/WjNZ6GfzMWsq2DcGjElpV9it8JmETHm9mAJuOJNhuJcWJxt8ltCJabONFRpDFq1A/DP0d0KFj9CTJVM4VA== - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -regenerate-unicode-properties@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" - integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regenerator-transform@^0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" - integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== - dependencies: - "@babel/runtime" "^7.8.4" - -regexpu-core@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.1.1.tgz#b469b245594cb2d088ceebc6369dceb8c00becac" - integrity sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.2.0" - regjsgen "^0.8.0" - regjsparser "^0.11.0" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.1.0" - -regjsgen@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" - integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== - -regjsparser@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.11.1.tgz#ae55c74f646db0c8fcb922d4da635e33da405149" - integrity sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ== - dependencies: - jsesc "~3.0.2" - -resolve@^1.14.2: - version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -rimraf@5: - version "5.0.10" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" - integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== - dependencies: - glob "^10.3.7" - -rollup-plugin-banner2@^1.2.3: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-banner2/-/rollup-plugin-banner2-1.3.0.tgz#dbdabe5f6ef2616436120afdd3d8d000905b5e89" - integrity sha512-ehXBo4ziTayAwtyeNTc0Gc3IVBI6pqMtdvoX7B88WJHBXzA3BrUUvAQ7OSNOLB3ulgZyugDJypNh1PrFR3uiVQ== - dependencies: - magic-string "^0.25.7" - -rollup-plugin-prettier@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-prettier/-/rollup-plugin-prettier-4.1.1.tgz#eb74bd47c3cc3ba68bdf34b5323d0d7a47be8cec" - integrity sha512-ugpi/EqW12yJa4NO3o4f/wt/YHwiQovVGC2jxZgxuKO9osjt4lVxVA427+itl87XmQc6089ZkpDc6OpaOZKWgQ== - dependencies: - "@types/prettier" "^1.0.0 || ^2.0.0 || ^3.0.0" - diff "5.1.0" - lodash.hasin "4.5.2" - lodash.isempty "4.4.0" - lodash.isnil "4.0.0" - lodash.omitby "4.6.0" - magic-string "0.30.5" - -rollup@^4.22.4: - version "4.24.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" - integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== - dependencies: - "@types/estree" "1.0.6" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.24.0" - "@rollup/rollup-android-arm64" "4.24.0" - "@rollup/rollup-darwin-arm64" "4.24.0" - "@rollup/rollup-darwin-x64" "4.24.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" - "@rollup/rollup-linux-arm-musleabihf" "4.24.0" - "@rollup/rollup-linux-arm64-gnu" "4.24.0" - "@rollup/rollup-linux-arm64-musl" "4.24.0" - "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" - "@rollup/rollup-linux-riscv64-gnu" "4.24.0" - "@rollup/rollup-linux-s390x-gnu" "4.24.0" - "@rollup/rollup-linux-x64-gnu" "4.24.0" - "@rollup/rollup-linux-x64-musl" "4.24.0" - "@rollup/rollup-win32-arm64-msvc" "4.24.0" - "@rollup/rollup-win32-ia32-msvc" "4.24.0" - "@rollup/rollup-win32-x64-msvc" "4.24.0" - fsevents "~2.3.2" - -safe-buffer@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -scheduler@0.25.0-beta-26f2496093-20240514: - version "0.25.0-beta-26f2496093-20240514" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0-beta-26f2496093-20240514.tgz#a3bc0ff694ec6de7a78c1e48e1f8f4a8555bd77d" - integrity sha512-vDwOytLHFnA3SW2B1lNcbO+/qKVyLCX+KLpm+tRGNDsXpyxzRgkIaYGWmX+S70AJGchUHCtuqQ50GFeFgDbXUw== - -semver@^5.6.0: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -serialize-javascript@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - -smob@^1.0.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab" - integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig== - -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - -"string-width-cjs@npm:string-width@^4.2.0": - 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@^4.1.0: - 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" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - -"strip-ansi-cjs@npm: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@^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" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== - dependencies: - ansi-regex "^6.0.1" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -terser@^5.17.4: - version "5.34.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.34.1.tgz#af40386bdbe54af0d063e0670afd55c3105abeb6" - integrity sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" - integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71" - integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" - integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== - -update-browserslist-db@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" - integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== - dependencies: - escalade "^3.2.0" - picocolors "^1.1.0" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -"wrap-ansi-cjs@npm: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" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - -zod-validation-error@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-2.1.0.tgz#208eac75237dfed47c0018d2fe8fd03501bfc9ac" - integrity sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ== - -zod@^3.22.4: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== diff --git a/compiler/fixtures/runtime-compat/setup.sh b/compiler/fixtures/runtime-compat/setup.sh deleted file mode 100755 index c1cd6dc09b60e..0000000000000 --- a/compiler/fixtures/runtime-compat/setup.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# 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. - -set -eo pipefail - -HERE=$(pwd) - -cd lib && yarn --silent link -cd $HERE/app-18 && yarn --silent link runtime-compat-lib -cd $HERE/app-19 && yarn --silent link runtime-compat-lib From 156eab2f7b34fe78ef26a1752f95bfdc2092819d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 5 Nov 2024 15:05:04 -0500 Subject: [PATCH 337/426] Fork the "empty" prepareStackTrace case for Server builds (#31427) We don't actually want the source mapped version of `.stack` from errors because that would cause us to not be able to associate it with a source map in the UIs that need it. The strategy in browsers is more correct where the display is responsible for source maps. That's why we disable any custom `prepareStackTrace` like the ones added by `source-map`. We reset it to `undefined`. However, when running node with `--enable-source-maps` the default for `prepareStackTrace` which is a V8 feature (but may exist elsewhere too like Bun) is a source mapped version of the stack. In those environments we need to reset it to a default implementation that doesn't apply source maps. We already did this in Flight using the `ReactFlightStackConfigV8.js` config. However, we need this more generally in the `shared/ReactComponentStackFrame` implementation. We could always set it to the default implementation instead of `undefined` but that's unnecessary code in browser builds and it might lead to slightly different results. For safety and code size, this PR does it with a fork instead. All builds specific to `node` or `edge` (or `markup` which is a server feature) gets the default implementation where as everything else (e.g. browsers) get `undefined` since it's expected that this is not source mapped. We don't have to do anything about the equivalent in React DevTools since React DevTools doesn't run on the server. --- .../src/ReactFlightStackConfigV8.js | 15 +-- packages/shared/DefaultPrepareStackTrace.js | 12 +++ packages/shared/DefaultPrepareStackTraceV8.js | 25 +++++ packages/shared/ReactComponentStackFrame.js | 5 +- packages/shared/ReactOwnerStackFrames.js | 5 +- .../DefaultPrepareStackTrace.dom-edge.js | 10 ++ .../DefaultPrepareStackTrace.dom-node.js | 10 ++ .../forks/DefaultPrepareStackTrace.markup.js | 10 ++ scripts/rollup/forks.js | 30 ++++++ scripts/shared/inlinedHostConfigs.js | 100 ++++++++---------- 10 files changed, 150 insertions(+), 72 deletions(-) create mode 100644 packages/shared/DefaultPrepareStackTrace.js create mode 100644 packages/shared/DefaultPrepareStackTraceV8.js create mode 100644 packages/shared/forks/DefaultPrepareStackTrace.dom-edge.js create mode 100644 packages/shared/forks/DefaultPrepareStackTrace.dom-node.js create mode 100644 packages/shared/forks/DefaultPrepareStackTrace.markup.js diff --git a/packages/react-server/src/ReactFlightStackConfigV8.js b/packages/react-server/src/ReactFlightStackConfigV8.js index 71465e3c5f536..981e62dbdbb5f 100644 --- a/packages/react-server/src/ReactFlightStackConfigV8.js +++ b/packages/react-server/src/ReactFlightStackConfigV8.js @@ -9,18 +9,7 @@ import type {ReactStackTrace} from 'shared/ReactTypes'; -function prepareStackTrace( - error: Error, - structuredStackTrace: CallSite[], -): string { - const name = error.name || 'Error'; - const message = error.message || ''; - let stack = name + ': ' + message; - for (let i = 0; i < structuredStackTrace.length; i++) { - stack += '\n at ' + structuredStackTrace[i].toString(); - } - return stack; -} +import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace'; function getStack(error: Error): string { // We override Error.prepareStackTrace with our own version that normalizes @@ -30,7 +19,7 @@ function getStack(error: Error): string { // eagerly on the server. If the stack has already been read, then we might // not get a normalized stack and it might still have been source mapped. const previousPrepare = Error.prepareStackTrace; - Error.prepareStackTrace = prepareStackTrace; + Error.prepareStackTrace = DefaultPrepareStackTrace; try { // eslint-disable-next-line react-internal/safe-string-coercion return String(error.stack); diff --git a/packages/shared/DefaultPrepareStackTrace.js b/packages/shared/DefaultPrepareStackTrace.js new file mode 100644 index 0000000000000..5e0e3dc0da9df --- /dev/null +++ b/packages/shared/DefaultPrepareStackTrace.js @@ -0,0 +1,12 @@ +/** + * 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 + */ + +// This is forked in server builds where the default stack frame may be source mapped. + +export default ((undefined: any): (Error, CallSite[]) => string); diff --git a/packages/shared/DefaultPrepareStackTraceV8.js b/packages/shared/DefaultPrepareStackTraceV8.js new file mode 100644 index 0000000000000..200c64b69d685 --- /dev/null +++ b/packages/shared/DefaultPrepareStackTraceV8.js @@ -0,0 +1,25 @@ +/** + * 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 + */ + +// This file replaces DefaultPrepareStackTrace in Edge/Node Server builds. + +function prepareStackTrace( + error: Error, + structuredStackTrace: CallSite[], +): string { + const name = error.name || 'Error'; + const message = error.message || ''; + let stack = name + ': ' + message; + for (let i = 0; i < structuredStackTrace.length; i++) { + stack += '\n at ' + structuredStackTrace[i].toString(); + } + return stack; +} + +export default prepareStackTrace; diff --git a/packages/shared/ReactComponentStackFrame.js b/packages/shared/ReactComponentStackFrame.js index bef56120ff4a2..96f69617e607b 100644 --- a/packages/shared/ReactComponentStackFrame.js +++ b/packages/shared/ReactComponentStackFrame.js @@ -23,6 +23,8 @@ import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev'; import ReactSharedInternals from 'shared/ReactSharedInternals'; +import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace'; + let prefix; let suffix; export function describeBuiltInComponentFrame(name: string): string { @@ -92,8 +94,7 @@ export function describeNativeComponentFrame( reentry = true; const previousPrepareStackTrace = Error.prepareStackTrace; - // $FlowFixMe[incompatible-type] It does accept undefined. - Error.prepareStackTrace = undefined; + Error.prepareStackTrace = DefaultPrepareStackTrace; let previousDispatcher = null; if (__DEV__) { diff --git a/packages/shared/ReactOwnerStackFrames.js b/packages/shared/ReactOwnerStackFrames.js index 829930430ada8..d7543858f1281 100644 --- a/packages/shared/ReactOwnerStackFrames.js +++ b/packages/shared/ReactOwnerStackFrames.js @@ -7,10 +7,11 @@ * @flow */ +import DefaultPrepareStackTrace from 'shared/DefaultPrepareStackTrace'; + export function formatOwnerStack(error: Error): string { const prevPrepareStackTrace = Error.prepareStackTrace; - // $FlowFixMe[incompatible-type] It does accept undefined. - Error.prepareStackTrace = undefined; + Error.prepareStackTrace = DefaultPrepareStackTrace; let stack = error.stack; Error.prepareStackTrace = prevPrepareStackTrace; if (stack.startsWith('Error: react-stack-top-frame\n')) { diff --git a/packages/shared/forks/DefaultPrepareStackTrace.dom-edge.js b/packages/shared/forks/DefaultPrepareStackTrace.dom-edge.js new file mode 100644 index 0000000000000..b69f14e36a311 --- /dev/null +++ b/packages/shared/forks/DefaultPrepareStackTrace.dom-edge.js @@ -0,0 +1,10 @@ +/** + * 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 {default} from '../DefaultPrepareStackTraceV8'; diff --git a/packages/shared/forks/DefaultPrepareStackTrace.dom-node.js b/packages/shared/forks/DefaultPrepareStackTrace.dom-node.js new file mode 100644 index 0000000000000..b69f14e36a311 --- /dev/null +++ b/packages/shared/forks/DefaultPrepareStackTrace.dom-node.js @@ -0,0 +1,10 @@ +/** + * 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 {default} from '../DefaultPrepareStackTraceV8'; diff --git a/packages/shared/forks/DefaultPrepareStackTrace.markup.js b/packages/shared/forks/DefaultPrepareStackTrace.markup.js new file mode 100644 index 0000000000000..b69f14e36a311 --- /dev/null +++ b/packages/shared/forks/DefaultPrepareStackTrace.markup.js @@ -0,0 +1,10 @@ +/** + * 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 {default} from '../DefaultPrepareStackTraceV8'; diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index 8539ce7f7cc03..2d6f718c76360 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -217,6 +217,36 @@ const forks = Object.freeze({ } }, + './packages/shared/DefaultPrepareStackTrace.js': ( + bundleType, + entry, + dependencies, + moduleType + ) => { + if (moduleType !== RENDERER && moduleType !== RECONCILER) { + return null; + } + // eslint-disable-next-line no-for-of-loops/no-for-of-loops + for (let rendererInfo of inlinedHostConfigs) { + if (rendererInfo.entryPoints.indexOf(entry) !== -1) { + if (!rendererInfo.isServerSupported) { + return null; + } + const foundFork = findNearestExistingForkFile( + './packages/shared/forks/DefaultPrepareStackTrace.', + rendererInfo.shortName, + '.js' + ); + if (foundFork) { + return foundFork; + } + // fall through to error + break; + } + } + return null; + }, + './packages/react-reconciler/src/ReactFiberConfig.js': ( bundleType, entry, diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js index 514ecc4567b05..3fc9c7b010f16 100644 --- a/scripts/shared/inlinedHostConfigs.js +++ b/scripts/shared/inlinedHostConfigs.js @@ -8,12 +8,55 @@ module.exports = [ { - shortName: 'dom-node', + shortName: 'dom-browser', entryPoints: [ 'react-dom', 'react-dom/client', 'react-dom/profiling', 'react-dom/unstable_testing', + 'react-dom/src/server/react-dom-server.browser.js', + 'react-dom/static.browser', + 'react-dom/unstable_server-external-runtime', + 'react-server-dom-webpack/client.browser', + 'react-server-dom-webpack/src/server/react-flight-dom-server.browser', + ], + paths: [ + 'react-dom', + 'react-dom/src/ReactDOMReactServer.js', + 'react-dom-bindings', + 'react-dom/client', + 'react-dom/profiling', + 'react-dom/server.browser', + 'react-dom/static.browser', + 'react-dom/unstable_testing', + 'react-dom/src/server/react-dom-server.browser', + 'react-dom/src/server/ReactDOMFizzServerBrowser.js', // react-dom/server.browser + 'react-dom/src/server/ReactDOMFizzStaticBrowser.js', + 'react-dom-bindings/src/server/ReactDOMFlightServerHostDispatcher.js', + 'react-dom-bindings/src/server/ReactFlightServerConfigDOM.js', + 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM.js', + 'react-server-dom-webpack', + 'react-server-dom-webpack/client', + 'react-server-dom-webpack/client.browser', + 'react-server-dom-webpack/server.browser', + 'react-server-dom-webpack/static.browser', + 'react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js', // react-server-dom-webpack/client.browser + 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js', + 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpackBrowser.js', + 'react-server-dom-webpack/src/server/react-flight-dom-server.browser', + 'react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js', // react-server-dom-webpack/src/server/react-flight-dom-server.browser + 'react-devtools', + 'react-devtools-core', + 'react-devtools-shell', + 'react-devtools-shared', + 'shared/ReactDOMSharedInternals', + ], + isFlowTyped: true, + isServerSupported: true, + }, + { + shortName: 'dom-node', + entryPoints: [ 'react-dom/src/ReactDOMReactServer.js', 'react-dom/src/server/react-dom-server.node.js', 'react-dom/static.node', @@ -148,13 +191,7 @@ module.exports = [ }, { shortName: 'dom-bun', - entryPoints: [ - 'react-dom', - 'react-dom/client', - 'react-dom/profiling', - 'react-dom/unstable_testing', - 'react-dom/src/server/react-dom-server.bun.js', - ], + entryPoints: ['react-dom/src/server/react-dom-server.bun.js'], paths: [ 'react-dom', 'react-dom/client', @@ -171,53 +208,6 @@ module.exports = [ isFlowTyped: true, isServerSupported: true, }, - { - shortName: 'dom-browser', - entryPoints: [ - 'react-dom', - 'react-dom/client', - 'react-dom/profiling', - 'react-dom/unstable_testing', - 'react-dom/src/server/react-dom-server.browser.js', - 'react-dom/static.browser', - 'react-dom/unstable_server-external-runtime', - 'react-server-dom-webpack/client.browser', - 'react-server-dom-webpack/src/server/react-flight-dom-server.browser', - ], - paths: [ - 'react-dom', - 'react-dom/src/ReactDOMReactServer.js', - 'react-dom-bindings', - 'react-dom/client', - 'react-dom/profiling', - 'react-dom/server.browser', - 'react-dom/static.browser', - 'react-dom/unstable_testing', - 'react-dom/src/server/react-dom-server.browser', - 'react-dom/src/server/ReactDOMFizzServerBrowser.js', // react-dom/server.browser - 'react-dom/src/server/ReactDOMFizzStaticBrowser.js', - 'react-dom-bindings/src/server/ReactDOMFlightServerHostDispatcher.js', - 'react-dom-bindings/src/server/ReactFlightServerConfigDOM.js', - 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM.js', - 'react-server-dom-webpack', - 'react-server-dom-webpack/client', - 'react-server-dom-webpack/client.browser', - 'react-server-dom-webpack/server.browser', - 'react-server-dom-webpack/static.browser', - 'react-server-dom-webpack/src/client/ReactFlightDOMClientBrowser.js', // react-server-dom-webpack/client.browser - 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack.js', - 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpackBrowser.js', - 'react-server-dom-webpack/src/server/react-flight-dom-server.browser', - 'react-server-dom-webpack/src/server/ReactFlightDOMServerBrowser.js', // react-server-dom-webpack/src/server/react-flight-dom-server.browser - 'react-devtools', - 'react-devtools-core', - 'react-devtools-shell', - 'react-devtools-shared', - 'shared/ReactDOMSharedInternals', - ], - isFlowTyped: true, - isServerSupported: true, - }, { shortName: 'dom-browser-esm', entryPoints: ['react-server-dom-esm/client.browser'], From dd1a021bad0908d3ad7ba4314ca9a39173d7758f Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:25:39 -0500 Subject: [PATCH 338/426] [compiler][ez] Patch hoistability for ObjectMethods (#31197) Extends #31066 to ObjectMethods (somehow missed this before). ' --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31197). * #31204 * #31202 * #31203 * #31201 * #31200 * #31346 * #31199 * #31431 * #31345 * __->__ #31197 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 8 +- .../infer-objectmethod-cond-access.expect.md | 82 +++++++++++++++++++ .../infer-objectmethod-cond-access.js | 26 ++++++ 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index 80593d6275868..d2e7220159108 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -348,7 +348,8 @@ function collectNonNullsInBlocks( assumedNonNullObjects.add(maybeNonNull); } if ( - instr.value.kind === 'FunctionExpression' && + (instr.value.kind === 'FunctionExpression' || + instr.value.kind === 'ObjectMethod') && !fn.env.config.enableTreatFunctionDepsAsConditional ) { const innerFn = instr.value.loweredFunc; @@ -591,7 +592,10 @@ function collectFunctionExpressionFakeLoads( for (const [_, block] of fn.body.blocks) { for (const {lvalue, value} of block.instructions) { - if (value.kind === 'FunctionExpression') { + if ( + value.kind === 'FunctionExpression' || + value.kind === 'ObjectMethod' + ) { for (const reference of value.loweredFunc.dependencies) { let curr: IdentifierId | undefined = reference.identifier.id; while (curr != null) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md new file mode 100644 index 0000000000000..2c7bf6bbe599e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md @@ -0,0 +1,82 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR +import {Stringify} from 'shared-runtime'; + +function Foo({a, shouldReadA}) { + return ( + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +import { Stringify } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(3); + const { a, shouldReadA } = t0; + let t1; + if ($[0] !== shouldReadA || $[1] !== a) { + t1 = ( + + ); + $[0] = shouldReadA; + $[1] = a; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ a: null, shouldReadA: true }], + sequentialRenders: [ + { a: null, shouldReadA: true }, + { a: null, shouldReadA: false }, + { a: { b: { c: 4 } }, shouldReadA: true }, + ], +}; + +``` + +### Eval output +(kind: ok) [[ (exception in render) TypeError: Cannot read properties of null (reading 'b') ]] +
{"objectMethod":{"method":{"kind":"Function","result":null}},"shouldInvokeFns":true}
+
{"objectMethod":{"method":{"kind":"Function","result":4}},"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.js new file mode 100644 index 0000000000000..2c8488bb29216 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.js @@ -0,0 +1,26 @@ +// @enablePropagateDepsInHIR +import {Stringify} from 'shared-runtime'; + +function Foo({a, shouldReadA}) { + return ( + + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{a: null, shouldReadA: true}], + sequentialRenders: [ + {a: null, shouldReadA: true}, + {a: null, shouldReadA: false}, + {a: {b: {c: 4}}, shouldReadA: true}, + ], +}; From e7e269b7265ec94929a53f4d402037261c87cf44 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:25:54 -0500 Subject: [PATCH 339/426] [compiler] bugfix for hoistable deps for nested functions (#31345) `PropertyPathRegistry` is responsible for uniqueing identifier and property paths. This is necessary for the hoistability CFG merging logic which takes unions and intersections of these nodes to determine a basic block's hoistable reads, as a function of its neighbors. We also depend on this to merge optional chained and non-optional chained property paths This fixes a small bug in #31066 in which we create a new registry for nested functions. Now, we use the same registry for a component / hook and all its inner functions ' --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31345). * #31204 * #31202 * #31203 * #31201 * #31200 * #31346 * #31199 * #31431 * __->__ #31345 * #31197 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 100 +++++++++++------- .../src/HIR/PropagateScopeDependenciesHIR.ts | 2 +- .../repro-invariant.expect.md | 61 +++++++++++ .../repro-invariant.tsx | 14 +++ 4 files changed, 138 insertions(+), 39 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index d2e7220159108..456425aecaae9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -1,5 +1,6 @@ import {CompilerError} from '../CompilerError'; import {inRange} from '../ReactiveScopes/InferReactiveScopeVariables'; +import {printDependency} from '../ReactiveScopes/PrintReactiveFunction'; import { Set_equal, Set_filter, @@ -23,6 +24,8 @@ import { } from './HIR'; import {collectTemporariesSidemap} from './PropagateScopeDependenciesHIR'; +const DEBUG_PRINT = false; + /** * Helper function for `PropagateScopeDependencies`. Uses control flow graph * analysis to determine which `Identifier`s can be assumed to be non-null @@ -86,15 +89,8 @@ export function collectHoistablePropertyLoads( fn: HIRFunction, temporaries: ReadonlyMap, hoistableFromOptionals: ReadonlyMap, - nestedFnImmutableContext: ReadonlySet | null, ): ReadonlyMap { const registry = new PropertyPathRegistry(); - - const functionExpressionLoads = collectFunctionExpressionFakeLoads(fn); - const actuallyEvaluatedTemporaries = new Map( - [...temporaries].filter(([id]) => !functionExpressionLoads.has(id)), - ); - /** * Due to current limitations of mutable range inference, there are edge cases in * which we infer known-immutable values (e.g. props or hook params) to have a @@ -111,14 +107,51 @@ export function collectHoistablePropertyLoads( } } } - const nodes = collectNonNullsInBlocks(fn, { - temporaries: actuallyEvaluatedTemporaries, + return collectHoistablePropertyLoadsImpl(fn, { + temporaries, knownImmutableIdentifiers, hoistableFromOptionals, registry, - nestedFnImmutableContext, + nestedFnImmutableContext: null, }); - propagateNonNull(fn, nodes, registry); +} + +type CollectHoistablePropertyLoadsContext = { + temporaries: ReadonlyMap; + knownImmutableIdentifiers: ReadonlySet; + hoistableFromOptionals: ReadonlyMap; + registry: PropertyPathRegistry; + /** + * (For nested / inner function declarations) + * Context variables (i.e. captured from an outer scope) that are immutable. + * Note that this technically could be merged into `knownImmutableIdentifiers`, + * but are currently kept separate for readability. + */ + nestedFnImmutableContext: ReadonlySet | null; +}; +function collectHoistablePropertyLoadsImpl( + fn: HIRFunction, + context: CollectHoistablePropertyLoadsContext, +): ReadonlyMap { + const functionExpressionLoads = collectFunctionExpressionFakeLoads(fn); + const actuallyEvaluatedTemporaries = new Map( + [...context.temporaries].filter(([id]) => !functionExpressionLoads.has(id)), + ); + + const nodes = collectNonNullsInBlocks(fn, { + ...context, + temporaries: actuallyEvaluatedTemporaries, + }); + propagateNonNull(fn, nodes, context.registry); + + if (DEBUG_PRINT) { + console.log('(printing hoistable nodes in blocks)'); + for (const [blockId, node] of nodes) { + console.log( + `bb${blockId}: ${[...node.assumedNonNullObjects].map(n => printDependency(n.fullPath)).join(' ')}`, + ); + } + } return nodes; } @@ -243,7 +276,7 @@ class PropertyPathRegistry { function getMaybeNonNullInInstruction( instr: InstructionValue, - context: CollectNonNullsInBlocksContext, + context: CollectHoistablePropertyLoadsContext, ): PropertyPathNode | null { let path = null; if (instr.kind === 'PropertyLoad') { @@ -262,7 +295,7 @@ function getMaybeNonNullInInstruction( function isImmutableAtInstr( identifier: Identifier, instr: InstructionId, - context: CollectNonNullsInBlocksContext, + context: CollectHoistablePropertyLoadsContext, ): boolean { if (context.nestedFnImmutableContext != null) { /** @@ -295,22 +328,9 @@ function isImmutableAtInstr( } } -type CollectNonNullsInBlocksContext = { - temporaries: ReadonlyMap; - knownImmutableIdentifiers: ReadonlySet; - hoistableFromOptionals: ReadonlyMap; - registry: PropertyPathRegistry; - /** - * (For nested / inner function declarations) - * Context variables (i.e. captured from an outer scope) that are immutable. - * Note that this technically could be merged into `knownImmutableIdentifiers`, - * but are currently kept separate for readability. - */ - nestedFnImmutableContext: ReadonlySet | null; -}; function collectNonNullsInBlocks( fn: HIRFunction, - context: CollectNonNullsInBlocksContext, + context: CollectHoistablePropertyLoadsContext, ): ReadonlyMap { /** * Known non-null objects such as functional component props can be safely @@ -358,18 +378,22 @@ function collectNonNullsInBlocks( new Set(), ); const innerOptionals = collectOptionalChainSidemap(innerFn.func); - const innerHoistableMap = collectHoistablePropertyLoads( + const innerHoistableMap = collectHoistablePropertyLoadsImpl( innerFn.func, - innerTemporaries, - innerOptionals.hoistableObjects, - context.nestedFnImmutableContext ?? - new Set( - innerFn.func.context - .filter(place => - isImmutableAtInstr(place.identifier, instr.id, context), - ) - .map(place => place.identifier.id), - ), + { + ...context, + temporaries: innerTemporaries, // TODO: remove in later PR + hoistableFromOptionals: innerOptionals.hoistableObjects, // TODO: remove in later PR + nestedFnImmutableContext: + context.nestedFnImmutableContext ?? + new Set( + innerFn.func.context + .filter(place => + isImmutableAtInstr(place.identifier, instr.id, context), + ) + .map(place => place.identifier.id), + ), + }, ); const innerHoistables = assertNonNull( innerHoistableMap.get(innerFn.func.body.entry), diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index 855ca9121d26b..0178aea6e4c56 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -46,7 +46,7 @@ export function propagateScopeDependenciesHIR(fn: HIRFunction): void { const hoistablePropertyLoads = keyByScopeId( fn, - collectHoistablePropertyLoads(fn, temporaries, hoistableObjects, null), + collectHoistablePropertyLoads(fn, temporaries, hoistableObjects), ); const scopeDeps = collectDependencies( diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.expect.md new file mode 100644 index 0000000000000..73df2b615b9ef --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.expect.md @@ -0,0 +1,61 @@ + +## Input + +```javascript +// @enablePropagateDepsInHIR +import {Stringify} from 'shared-runtime'; + +function Foo({data}) { + return ( + data.a.d} bar={data.a?.b.c} shouldInvokeFns={true} /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{data: {a: null}}], + sequentialRenders: [{data: {a: {b: {c: 4}}}}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR +import { Stringify } from "shared-runtime"; + +function Foo(t0) { + const $ = _c(5); + const { data } = t0; + let t1; + if ($[0] !== data.a.d) { + t1 = () => data.a.d; + $[0] = data.a.d; + $[1] = t1; + } else { + t1 = $[1]; + } + const t2 = data.a?.b.c; + let t3; + if ($[2] !== t1 || $[3] !== t2) { + t3 = ; + $[2] = t1; + $[3] = t2; + $[4] = t3; + } else { + t3 = $[4]; + } + return t3; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ data: { a: null } }], + sequentialRenders: [{ data: { a: { b: { c: 4 } } } }], +}; + +``` + +### Eval output +(kind: ok)
{"foo":{"kind":"Function"},"bar":4,"shouldInvokeFns":true}
\ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.tsx new file mode 100644 index 0000000000000..05ed136d5f7a8 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/repro-invariant.tsx @@ -0,0 +1,14 @@ +// @enablePropagateDepsInHIR +import {Stringify} from 'shared-runtime'; + +function Foo({data}) { + return ( + data.a.d} bar={data.a?.b.c} shouldInvokeFns={true} /> + ); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{data: {a: null}}], + sequentialRenders: [{data: {a: {b: {c: 4}}}}], +}; From 527bcaa83d9d31e848ca1bea1a5b8532ab361527 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:27:39 -0500 Subject: [PATCH 340/426] [compiler] patch: rewrite scope dep/decl in inlineJsxTransform (#31431) This bugfix is needed to land #31199 PropagateScopeDepsHIR infers scope declarations for the `inline-jsx-transform` test fixture (the non-hir version does not). These declarations must get the rewritten phi identifiers --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31431). * #31204 * #31202 * #31203 * #31201 * #31200 * #31346 * #31199 * __->__ #31431 * #31345 * #31197 --- .../src/Optimization/InlineJsxTransform.ts | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 50822e78d977b..d97a4da1eccc4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -383,6 +383,30 @@ export function inlineJsxTransform( mapTerminalOperands(block.terminal, place => handlePlace(place, blockId, inlinedJsxDeclarations), ); + + if (block.terminal.kind === 'scope') { + const scope = block.terminal.scope; + for (const dep of scope.dependencies) { + dep.identifier = handleIdentifier( + dep.identifier, + inlinedJsxDeclarations, + ); + } + + for (const [origId, decl] of [...scope.declarations]) { + const newDecl = handleIdentifier( + decl.identifier, + inlinedJsxDeclarations, + ); + if (newDecl.id !== origId) { + scope.declarations.delete(origId); + scope.declarations.set(decl.identifier.id, { + identifier: newDecl, + scope: decl.scope, + }); + } + } + } } /** @@ -697,10 +721,10 @@ function handlePlace( inlinedJsxDeclaration == null || inlinedJsxDeclaration.blockIdsToIgnore.has(blockId) ) { - return {...place}; + return place; } - return {...place, identifier: {...inlinedJsxDeclaration.identifier}}; + return {...place, identifier: inlinedJsxDeclaration.identifier}; } function handlelValue( @@ -715,8 +739,20 @@ function handlelValue( inlinedJsxDeclaration == null || inlinedJsxDeclaration.blockIdsToIgnore.has(blockId) ) { - return {...lvalue}; + return lvalue; } - return {...lvalue, identifier: {...inlinedJsxDeclaration.identifier}}; + return {...lvalue, identifier: inlinedJsxDeclaration.identifier}; +} + +function handleIdentifier( + identifier: Identifier, + inlinedJsxDeclarations: InlinedJsxDeclarationMap, +): Identifier { + const inlinedJsxDeclaration = inlinedJsxDeclarations.get( + identifier.declarationId, + ); + return inlinedJsxDeclaration == null + ? identifier + : inlinedJsxDeclaration.identifier; } From 6c0f37f94b020279fb5ada70facc008fccb7172e Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Tue, 5 Nov 2024 15:49:20 -0500 Subject: [PATCH 341/426] [bundles] stop building legacy Paper renderer (#31429) --- scripts/rollup/bundles.js | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 26a88fb00811d..300caae37c030 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -696,40 +696,6 @@ const bundles = [ }), }, - /******* React Native *******/ - { - bundleTypes: __EXPERIMENTAL__ - ? [] - : [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING], - moduleType: RENDERER, - entry: 'react-native-renderer', - global: 'ReactNativeRenderer', - externals: ['react-native', 'ReactNativeInternalFeatureFlags'], - minifyWithProdErrorCodes: false, - wrapWithModuleBoundaries: true, - babel: opts => - Object.assign({}, opts, { - plugins: opts.plugins.concat([ - [require.resolve('@babel/plugin-transform-classes'), {loose: true}], - ]), - }), - }, - { - bundleTypes: [RN_OSS_DEV, RN_OSS_PROD, RN_OSS_PROFILING], - moduleType: RENDERER, - entry: 'react-native-renderer', - global: 'ReactNativeRenderer', - externals: ['react-native'], - minifyWithProdErrorCodes: false, - wrapWithModuleBoundaries: true, - babel: opts => - Object.assign({}, opts, { - plugins: opts.plugins.concat([ - [require.resolve('@babel/plugin-transform-classes'), {loose: true}], - ]), - }), - }, - /******* React Native Fabric *******/ { bundleTypes: __EXPERIMENTAL__ From f8f6e1a21a1cac64cf6faf666367d641b2d8b171 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Tue, 5 Nov 2024 16:04:02 -0500 Subject: [PATCH 342/426] [bundles] update GitHub actions for commit build branch (#31432) This is a followup to https://github.com/facebook/react/commit/6c0f37f94b020279fb5ada70facc008fccb7172e to unblock the job. --- .github/workflows/runtime_commit_artifacts.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 7842f07ba5888..37b8627be6251 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -137,7 +137,6 @@ jobs: # Delete OSS renderer. OSS renderer is synced through internal script. RENDERER_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/implementations/ rm $RENDERER_FOLDER/ReactFabric-{dev,prod,profiling}.js - rm $RENDERER_FOLDER/ReactNativeRenderer-{dev,prod,profiling}.js # Move React Native version file mv build/facebook-react-native/VERSION_NATIVE_FB ./compiled-rn/VERSION_NATIVE_FB From bddb7c9b5c248c77fb52743cd319945d782bb7aa Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:56:36 -0500 Subject: [PATCH 343/426] [compiler] Add fixture for objectexpr computed key bug (#31348) We were bailing out on complex computed-key syntax (prior to #31344) as we assumed that this caused bugs (due to inferring computed key rvalues to have `freeze` effects). This fixture shows that this bailout is unrelated to the underlying bug --- ...nstruction-hoisted-sequence-expr.expect.md | 109 ++++++++++++++++++ ...fter-construction-hoisted-sequence-expr.js | 31 +++++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 3 files changed, 141 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md new file mode 100644 index 0000000000000..dcca6cddd8fb2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md @@ -0,0 +1,109 @@ + +## Input + +```javascript +import {identity, mutate} from 'shared-runtime'; + +/** + * Bug: copy of error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr + * with the mutation hoisted to a named variable instead of being directly + * inlined into the Object key. + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * Forget: + * (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe","wat2":"joe"}] + */ +function Component(props) { + const key = {}; + const tmp = (mutate(key), key); + const context = { + // Here, `tmp` is frozen (as it's inferred to be a primitive/string) + [tmp]: 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 } from "shared-runtime"; + +/** + * Bug: copy of error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr + * with the mutation hoisted to a named variable instead of being directly + * inlined into the Object key. + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * Forget: + * (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe","wat2":"joe"}] + */ +function Component(props) { + const $ = _c(8); + let t0; + let key; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + key = {}; + t0 = (mutate(key), key); + $[0] = t0; + $[1] = key; + } else { + t0 = $[0]; + key = $[1]; + } + const tmp = t0; + let t1; + if ($[2] !== props.value) { + t1 = identity([props.value]); + $[2] = props.value; + $[3] = t1; + } else { + t1 = $[3]; + } + let t2; + if ($[4] !== t1) { + t2 = { [tmp]: t1 }; + $[4] = t1; + $[5] = t2; + } else { + t2 = $[5]; + } + const context = t2; + + mutate(key); + let t3; + if ($[6] !== context) { + t3 = [context, key]; + $[6] = context; + $[7] = t3; + } else { + t3 = $[7]; + } + return t3; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ value: 42 }], + sequentialRenders: [{ value: 42 }, { value: 42 }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.js new file mode 100644 index 0000000000000..94befbdd17b77 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.js @@ -0,0 +1,31 @@ +import {identity, mutate} from 'shared-runtime'; + +/** + * Bug: copy of error.todo-object-expression-computed-key-modified-during-after-construction-sequence-expr + * with the mutation hoisted to a named variable instead of being directly + * inlined into the Object key. + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * Forget: + * (kind: ok) [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe"}] + * [{"[object Object]":[42]},{"wat0":"joe","wat1":"joe","wat2":"joe"}] + */ +function Component(props) { + const key = {}; + const tmp = (mutate(key), key); + const context = { + // Here, `tmp` is frozen (as it's inferred to be a primitive/string) + [tmp]: identity([props.value]), + }; + mutate(key); + return [context, key]; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{value: 42}], + sequentialRenders: [{value: 42}, {value: 42}], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 351f242e40820..76914f1dd28a5 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -478,6 +478,7 @@ const skipFilter = new Set([ // bugs 'fbt/bug-fbt-plural-multiple-function-calls', 'fbt/bug-fbt-plural-multiple-mixed-call-tag', + 'bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr', 'bug-invalid-hoisting-functionexpr', 'bug-try-catch-maybe-null-dependency', 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted', From 5ca2bc6d631dde8c221fa482cb8729a67115c7f9 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:56:53 -0500 Subject: [PATCH 344/426] [compiler][ez] Fixture repro for function hoisting bug (#31349) Repro for bug reported by @alexmckenley --- .../bug-functiondecl-hoisting.expect.md | 81 +++++++++++++++++++ .../compiler/bug-functiondecl-hoisting.tsx | 22 +++++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 3 files changed, 104 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md new file mode 100644 index 0000000000000..2b0031b117be2 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.expect.md @@ -0,0 +1,81 @@ + +## Input + +```javascript +import {Stringify} from 'shared-runtime'; + +/** + * Fixture currently fails with + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok)
{"result":{"value":2},"fn":{"kind":"Function","result":{"value":2}},"shouldInvokeFns":true}
+ * Forget: + * (kind: exception) bar is not a function + */ +function Foo({value}) { + const result = bar(); + function bar() { + return {value}; + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{value: 2}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { Stringify } from "shared-runtime"; + +/** + * Fixture currently fails with + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok)
{"result":{"value":2},"fn":{"kind":"Function","result":{"value":2}},"shouldInvokeFns":true}
+ * Forget: + * (kind: exception) bar is not a function + */ +function Foo(t0) { + const $ = _c(6); + const { value } = t0; + let bar; + let result; + if ($[0] !== value) { + result = bar(); + bar = function bar() { + return { value }; + }; + $[0] = value; + $[1] = bar; + $[2] = result; + } else { + bar = $[1]; + result = $[2]; + } + + const t1 = bar; + let t2; + if ($[3] !== result || $[4] !== t1) { + t2 = ; + $[3] = result; + $[4] = t1; + $[5] = t2; + } else { + t2 = $[5]; + } + return t2; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{ value: 2 }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.tsx new file mode 100644 index 0000000000000..c454101282994 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-functiondecl-hoisting.tsx @@ -0,0 +1,22 @@ +import {Stringify} from 'shared-runtime'; + +/** + * Fixture currently fails with + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok)
{"result":{"value":2},"fn":{"kind":"Function","result":{"value":2}},"shouldInvokeFns":true}
+ * Forget: + * (kind: exception) bar is not a function + */ +function Foo({value}) { + const result = bar(); + function bar() { + return {value}; + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Foo, + params: [{value: 2}], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 76914f1dd28a5..b868afc52b82d 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -480,6 +480,7 @@ const skipFilter = new Set([ 'fbt/bug-fbt-plural-multiple-mixed-call-tag', 'bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr', 'bug-invalid-hoisting-functionexpr', + 'bug-functiondecl-hoisting', 'bug-try-catch-maybe-null-dependency', 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted', 'bug-invalid-phi-as-dependency', From 33195602ea125af38f9460f0bb2ccab8713e5f10 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:57:18 -0500 Subject: [PATCH 345/426] [compiler][ez] tsconfig: treat all snap fixtures as modules (#31350) Qol improvement. Currently, typescript lints treat test fixtures without an export as a 'global script' (see [docs](https://www.typescriptlang.org/docs/handbook/2/modules.html#how-javascript-modules-are-defined)). This gives confusing lints for duplicate declarations (in the global scope) --- .../src/__tests__/fixtures/tsconfig.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/tsconfig.json b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/tsconfig.json index 07d6d2baae402..7c51d213ede6e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/tsconfig.json +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/tsconfig.json @@ -19,7 +19,9 @@ }, "verbatimModuleSyntax": true, "module": "ESNext", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "moduleDetection": "force" + }, "include": [ "./compiler/**/*.js", From 792fa065ca7a46ce4a583e8f6f35eec8bd813d43 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:19:44 -0500 Subject: [PATCH 346/426] [compiler][ez] Clean up pragma parsing for tests + playground (#31347) Move environment config parsing for `inlineJsxTransform`, `lowerContextAccess`, and some dev-only options out of snap (test fixture). These should now be available for playground via `@inlineJsxTransform` and `lowerContextAccess`. Other small change: Changed zod fields from `nullish()` -> `nullable().default(null)`. [`nullish`](https://zod.dev/?id=nullish) fields accept `null | undefined` and default to `undefined`. We don't distinguish between null and undefined for any of these options, so let's only accept null + default to null. This also makes EnvironmentConfig in the playground more accurate. Previously, some fields just didn't show up as `prettyFormat({field: undefined})` does not print `field`. --- .../components/Editor/EditorImpl.tsx | 4 +- .../src/HIR/Environment.ts | 95 +++++++++++++------ .../src/HIR/index.ts | 2 +- ...codegen-emit-imports-same-source.expect.md | 4 +- .../codegen-emit-imports-same-source.js | 2 +- ...en-instrument-forget-gating-test.expect.md | 4 +- .../codegen-instrument-forget-gating-test.js | 2 +- .../codegen-instrument-forget-test.expect.md | 4 +- .../codegen-instrument-forget-test.js | 2 +- .../compiler/inline-jsx-transform.expect.md | 4 +- .../fixtures/compiler/inline-jsx-transform.js | 2 +- .../src/__tests__/parseConfigPragma-test.ts | 6 +- .../babel-plugin-react-compiler/src/index.ts | 2 +- compiler/packages/snap/src/compiler.ts | 74 +++------------ compiler/packages/snap/src/runner-worker.ts | 8 +- 15 files changed, 101 insertions(+), 114 deletions(-) diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index 9911c15cd77c6..1bdd372ad2b71 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -14,7 +14,7 @@ import { CompilerErrorDetail, Effect, ErrorSeverity, - parseConfigPragma, + parseConfigPragmaForTests, ValueKind, runPlayground, type Hook, @@ -208,7 +208,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] { try { // Extract the first line to quickly check for custom test directives const pragma = source.substring(0, source.indexOf('\n')); - const config = parseConfigPragma(pragma); + const config = parseConfigPragmaForTests(pragma); for (const fn of parseFunctions(source, language)) { const id = withIdentifier(getFunctionIdentifier(fn)); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 3e2b5597ac446..1189f2e125886 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -69,8 +69,8 @@ export const ExternalFunctionSchema = z.object({ export const InstrumentationSchema = z .object({ fn: ExternalFunctionSchema, - gating: ExternalFunctionSchema.nullish(), - globalGating: z.string().nullish(), + gating: ExternalFunctionSchema.nullable(), + globalGating: z.string().nullable(), }) .refine( opts => opts.gating != null || opts.globalGating != null, @@ -147,7 +147,7 @@ export type Hook = z.infer; */ const EnvironmentConfigSchema = z.object({ - customHooks: z.map(z.string(), HookSchema).optional().default(new Map()), + customHooks: z.map(z.string(), HookSchema).default(new Map()), /** * A function that, given the name of a module, can optionally return a description @@ -248,7 +248,7 @@ const EnvironmentConfigSchema = z.object({ * * The symbol configuration is set for backwards compatability with pre-React 19 transforms */ - inlineJsxTransform: ReactElementSymbolSchema.nullish(), + inlineJsxTransform: ReactElementSymbolSchema.nullable().default(null), /* * Enable validation of hooks to partially check that the component honors the rules of hooks. @@ -339,9 +339,9 @@ const EnvironmentConfigSchema = z.object({ * } * } */ - enableEmitFreeze: ExternalFunctionSchema.nullish(), + enableEmitFreeze: ExternalFunctionSchema.nullable().default(null), - enableEmitHookGuards: ExternalFunctionSchema.nullish(), + enableEmitHookGuards: ExternalFunctionSchema.nullable().default(null), /** * Enable instruction reordering. See InstructionReordering.ts for the details @@ -425,7 +425,7 @@ const EnvironmentConfigSchema = z.object({ * } * */ - enableEmitInstrumentForget: InstrumentationSchema.nullish(), + enableEmitInstrumentForget: InstrumentationSchema.nullable().default(null), // Enable validation of mutable ranges assertValidMutableRanges: z.boolean().default(false), @@ -464,8 +464,6 @@ const EnvironmentConfigSchema = z.object({ */ throwUnknownException__testonly: z.boolean().default(false), - enableSharedRuntime__testonly: z.boolean().default(false), - /** * Enables deps of a function epxression to be treated as conditional. This * makes sure we don't load a dep when it's a property (to check if it has @@ -503,7 +501,8 @@ const EnvironmentConfigSchema = z.object({ * computed one. This detects cases where rules of react violations may cause the * compiled code to behave differently than the original. */ - enableChangeDetectionForDebugging: ExternalFunctionSchema.nullish(), + enableChangeDetectionForDebugging: + ExternalFunctionSchema.nullable().default(null), /** * The react native re-animated library uses custom Babel transforms that @@ -543,7 +542,7 @@ const EnvironmentConfigSchema = z.object({ * * Here the variables `ref` and `myRef` will be typed as Refs. */ - enableTreatRefLikeIdentifiersAsRefs: z.boolean().nullable().default(false), + enableTreatRefLikeIdentifiersAsRefs: z.boolean().default(false), /* * If specified a value, the compiler lowers any calls to `useContext` to use @@ -565,12 +564,57 @@ const EnvironmentConfigSchema = z.object({ * const {foo, bar} = useCompiledContext(MyContext, (c) => [c.foo, c.bar]); * ``` */ - lowerContextAccess: ExternalFunctionSchema.nullish(), + lowerContextAccess: ExternalFunctionSchema.nullable().default(null), }); export type EnvironmentConfig = z.infer; -export function parseConfigPragma(pragma: string): EnvironmentConfig { +/** + * For test fixtures and playground only. + * + * Pragmas are straightforward to parse for boolean options (`:true` and + * `:false`). These are 'enabled' config values for non-boolean configs (i.e. + * what is used when parsing `:true`). + */ +const testComplexConfigDefaults: PartialEnvironmentConfig = { + validateNoCapitalizedCalls: [], + enableChangeDetectionForDebugging: { + source: 'react-compiler-runtime', + importSpecifierName: '$structuralCheck', + }, + enableEmitFreeze: { + source: 'react-compiler-runtime', + importSpecifierName: 'makeReadOnly', + }, + enableEmitInstrumentForget: { + fn: { + source: 'react-compiler-runtime', + importSpecifierName: 'useRenderCounter', + }, + gating: { + source: 'react-compiler-runtime', + importSpecifierName: 'shouldInstrument', + }, + globalGating: '__DEV__', + }, + enableEmitHookGuards: { + source: 'react-compiler-runtime', + importSpecifierName: '$dispatcherGuard', + }, + inlineJsxTransform: { + elementSymbol: 'react.transitional.element', + globalDevVar: 'DEV', + }, + lowerContextAccess: { + source: 'react-compiler-runtime', + importSpecifierName: 'useContext_withSelector', + }, +}; + +/** + * For snap test fixtures and playground only. + */ +export function parseConfigPragmaForTests(pragma: string): EnvironmentConfig { const maybeConfig: any = {}; // Get the defaults to programmatically check for boolean properties const defaultConfig = EnvironmentConfigSchema.parse({}); @@ -580,21 +624,12 @@ export function parseConfigPragma(pragma: string): EnvironmentConfig { continue; } const keyVal = token.slice(1); - let [key, val]: any = keyVal.split(':'); - - if (key === 'validateNoCapitalizedCalls') { - maybeConfig[key] = []; - continue; - } + let [key, val = undefined] = keyVal.split(':'); + const isSet = val === undefined || val === 'true'; - if ( - key === 'enableChangeDetectionForDebugging' && - (val === undefined || val === 'true') - ) { - maybeConfig[key] = { - source: 'react-compiler-runtime', - importSpecifierName: '$structuralCheck', - }; + if (isSet && key in testComplexConfigDefaults) { + maybeConfig[key] = + testComplexConfigDefaults[key as keyof PartialEnvironmentConfig]; continue; } @@ -609,7 +644,6 @@ export function parseConfigPragma(pragma: string): EnvironmentConfig { props.push({type: 'name', name: elt}); } } - console.log([valSplit[0], props.map(x => x.name ?? '*').join('.')]); maybeConfig[key] = [[valSplit[0], props]]; } continue; @@ -620,11 +654,10 @@ export function parseConfigPragma(pragma: string): EnvironmentConfig { continue; } if (val === undefined || val === 'true') { - val = true; + maybeConfig[key] = true; } else { - val = false; + maybeConfig[key] = false; } - maybeConfig[key] = val; } const config = EnvironmentConfigSchema.safeParse(maybeConfig); diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/index.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/index.ts index a0fd782572fc6..45267dd9a1833 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/index.ts @@ -17,7 +17,7 @@ export {buildReactiveScopeTerminalsHIR} from './BuildReactiveScopeTerminalsHIR'; export {computeDominatorTree, computePostDominatorTree} from './Dominator'; export { Environment, - parseConfigPragma, + parseConfigPragmaForTests, validateEnvironmentConfig, type EnvironmentConfig, type ExternalFunction, diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md index dd67bcfbff021..9a59b36cc0f10 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @enableEmitFreeze @instrumentForget +// @enableEmitFreeze @enableEmitInstrumentForget function useFoo(props) { return foo(props.x); @@ -18,7 +18,7 @@ import { shouldInstrument, makeReadOnly, } from "react-compiler-runtime"; -import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @instrumentForget +import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget function useFoo(props) { if (__DEV__ && shouldInstrument) diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.js index 4edff1c3fcaeb..bd66353319d6b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-emit-imports-same-source.js @@ -1,4 +1,4 @@ -// @enableEmitFreeze @instrumentForget +// @enableEmitFreeze @enableEmitInstrumentForget function useFoo(props) { return foo(props.x); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.expect.md index 4aa29992eb99b..fc9247344d56c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @instrumentForget @compilationMode(annotation) @gating +// @enableEmitInstrumentForget @compilationMode(annotation) @gating function Bar(props) { 'use forget'; @@ -25,7 +25,7 @@ function Foo(props) { ```javascript import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag"; import { useRenderCounter, shouldInstrument } from "react-compiler-runtime"; -import { c as _c } from "react/compiler-runtime"; // @instrumentForget @compilationMode(annotation) @gating +import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation) @gating const Bar = isForgetEnabled_Fixtures() ? function Bar(props) { "use forget"; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.js index 85fbd97ee7b96..dffb8ce795357 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-gating-test.js @@ -1,4 +1,4 @@ -// @instrumentForget @compilationMode(annotation) @gating +// @enableEmitInstrumentForget @compilationMode(annotation) @gating function Bar(props) { 'use forget'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md index ba8ed5056b3a0..b5da853b6e5c7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @instrumentForget @compilationMode(annotation) +// @enableEmitInstrumentForget @compilationMode(annotation) function Bar(props) { 'use forget'; @@ -24,7 +24,7 @@ function Foo(props) { ```javascript import { useRenderCounter, shouldInstrument } from "react-compiler-runtime"; -import { c as _c } from "react/compiler-runtime"; // @instrumentForget @compilationMode(annotation) +import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget @compilationMode(annotation) function Bar(props) { "use forget"; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.js index 894750327748b..2aef527e6be73 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/codegen-instrument-forget-test.js @@ -1,4 +1,4 @@ -// @instrumentForget @compilationMode(annotation) +// @enableEmitInstrumentForget @compilationMode(annotation) function Bar(props) { 'use forget'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md index e657e36d36ee9..f622b3a6fd667 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @enableInlineJsxTransform +// @inlineJsxTransform function Parent({children, a: _a, b: _b, c: _c, ref}) { return
{children}
; @@ -76,7 +76,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c2 } from "react/compiler-runtime"; // @enableInlineJsxTransform +import { c as _c2 } from "react/compiler-runtime"; // @inlineJsxTransform function Parent(t0) { const $ = _c2(2); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js index bebb7ad53b80f..ca55cab4ff60a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js @@ -1,4 +1,4 @@ -// @enableInlineJsxTransform +// @inlineJsxTransform function Parent({children, a: _a, b: _b, c: _c, ref}) { return
{children}
; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts index 706563b33b457..d634bd235f190 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/parseConfigPragma-test.ts @@ -5,9 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import {parseConfigPragma, validateEnvironmentConfig} from '..'; +import {parseConfigPragmaForTests, validateEnvironmentConfig} from '..'; -describe('parseConfigPragma()', () => { +describe('parseConfigPragmaForTests()', () => { it('parses flags in various forms', () => { const defaultConfig = validateEnvironmentConfig({}); @@ -17,7 +17,7 @@ describe('parseConfigPragma()', () => { expect(defaultConfig.validateNoSetStateInPassiveEffects).toBe(false); expect(defaultConfig.validateNoSetStateInRender).toBe(true); - const config = parseConfigPragma( + const config = parseConfigPragmaForTests( '@enableUseTypeAnnotations @validateNoSetStateInPassiveEffects:true @validateNoSetStateInRender:false', ); expect(config).toEqual({ diff --git a/compiler/packages/babel-plugin-react-compiler/src/index.ts b/compiler/packages/babel-plugin-react-compiler/src/index.ts index 256da2e5ed5c6..60a7e7843ce9b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/index.ts @@ -26,7 +26,7 @@ export { export { Effect, ValueKind, - parseConfigPragma, + parseConfigPragmaForTests, printHIR, validateEnvironmentConfig, type EnvironmentConfig, diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index f0ee88f06e037..95af40d62a880 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -21,10 +21,9 @@ import type { } from 'babel-plugin-react-compiler/src/Entrypoint'; import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR'; import type { - EnvironmentConfig, Macro, MacroMethod, - parseConfigPragma as ParseConfigPragma, + parseConfigPragmaForTests as ParseConfigPragma, } from 'babel-plugin-react-compiler/src/HIR/Environment'; import * as HermesParser from 'hermes-parser'; import invariant from 'invariant'; @@ -37,6 +36,11 @@ export function parseLanguage(source: string): 'flow' | 'typescript' { return source.indexOf('@flow') !== -1 ? 'flow' : 'typescript'; } +/** + * Parse react compiler plugin + environment options from test fixture. Note + * that although this primarily uses `Environment:parseConfigPragma`, it also + * has test fixture specific (i.e. not applicable to playground) parsing logic. + */ function makePluginOptions( firstLine: string, parseConfigPragmaFn: typeof ParseConfigPragma, @@ -44,15 +48,11 @@ function makePluginOptions( ValueKindEnum: typeof ValueKind, ): [PluginOptions, Array<{filename: string | null; event: LoggerEvent}>] { let gating = null; - let enableEmitInstrumentForget = null; - let enableEmitFreeze = null; - let enableEmitHookGuards = null; let compilationMode: CompilationMode = 'all'; let panicThreshold: PanicThresholdOptions = 'all_errors'; let hookPattern: string | null = null; // TODO(@mofeiZ) rewrite snap fixtures to @validatePreserveExistingMemo:false let validatePreserveExistingMemoizationGuarantees = false; - let enableChangeDetectionForDebugging = null; let customMacros: null | Array = null; let validateBlocklistedImports = null; let target = '19' as const; @@ -78,31 +78,6 @@ function makePluginOptions( importSpecifierName: 'isForgetEnabled_Fixtures', }; } - if (firstLine.includes('@instrumentForget')) { - enableEmitInstrumentForget = { - fn: { - source: 'react-compiler-runtime', - importSpecifierName: 'useRenderCounter', - }, - gating: { - source: 'react-compiler-runtime', - importSpecifierName: 'shouldInstrument', - }, - globalGating: '__DEV__', - }; - } - if (firstLine.includes('@enableEmitFreeze')) { - enableEmitFreeze = { - source: 'react-compiler-runtime', - importSpecifierName: 'makeReadOnly', - }; - } - if (firstLine.includes('@enableEmitHookGuards')) { - enableEmitHookGuards = { - source: 'react-compiler-runtime', - importSpecifierName: '$dispatcherGuard', - }; - } const targetMatch = /@target="([^"]+)"/.exec(firstLine); if (targetMatch) { @@ -132,16 +107,18 @@ function makePluginOptions( ignoreUseNoForget = true; } + /** + * Snap currently runs all fixtures without `validatePreserveExistingMemo` as + * most fixtures are interested in compilation output, not whether the + * compiler was able to preserve existing memo. + * + * TODO: flip the default. `useMemo` is rare in test fixtures -- fixtures that + * use useMemo should be explicit about whether this flag is enabled + */ if (firstLine.includes('@validatePreserveExistingMemoizationGuarantees')) { validatePreserveExistingMemoizationGuarantees = true; } - if (firstLine.includes('@enableChangeDetectionForDebugging')) { - enableChangeDetectionForDebugging = { - source: 'react-compiler-runtime', - importSpecifierName: '$structuralCheck', - }; - } const hookPatternMatch = /@hookPattern:"([^"]+)"/.exec(firstLine); if ( hookPatternMatch && @@ -197,22 +174,6 @@ function makePluginOptions( .filter(s => s.length > 0); } - let lowerContextAccess = null; - if (firstLine.includes('@lowerContextAccess')) { - lowerContextAccess = { - source: 'react-compiler-runtime', - importSpecifierName: 'useContext_withSelector', - }; - } - - let inlineJsxTransform: EnvironmentConfig['inlineJsxTransform'] = null; - if (firstLine.includes('@enableInlineJsxTransform')) { - inlineJsxTransform = { - elementSymbol: 'react.transitional.element', - globalDevVar: 'DEV', - }; - } - let logs: Array<{filename: string | null; event: LoggerEvent}> = []; let logger: Logger | null = null; if (firstLine.includes('@logger')) { @@ -232,17 +193,10 @@ function makePluginOptions( ValueKindEnum, }), customMacros, - enableEmitFreeze, - enableEmitInstrumentForget, - enableEmitHookGuards, assertValidMutableRanges: true, - enableSharedRuntime__testonly: true, hookPattern, validatePreserveExistingMemoizationGuarantees, - enableChangeDetectionForDebugging, - lowerContextAccess, validateBlocklistedImports, - inlineJsxTransform, }, compilationMode, logger, diff --git a/compiler/packages/snap/src/runner-worker.ts b/compiler/packages/snap/src/runner-worker.ts index 9447b2cddc52c..f05757d3df68d 100644 --- a/compiler/packages/snap/src/runner-worker.ts +++ b/compiler/packages/snap/src/runner-worker.ts @@ -7,7 +7,7 @@ import {codeFrameColumns} from '@babel/code-frame'; import type {PluginObj} from '@babel/core'; -import type {parseConfigPragma as ParseConfigPragma} from 'babel-plugin-react-compiler/src/HIR/Environment'; +import type {parseConfigPragmaForTests as ParseConfigPragma} from 'babel-plugin-react-compiler/src/HIR/Environment'; import {TransformResult, transformFixtureInput} from './compiler'; import { COMPILER_PATH, @@ -65,8 +65,8 @@ async function compile( COMPILER_INDEX_PATH, ); const {toggleLogging} = require(LOGGER_PATH); - const {parseConfigPragma} = require(PARSE_CONFIG_PRAGMA_PATH) as { - parseConfigPragma: typeof ParseConfigPragma; + const {parseConfigPragmaForTests} = require(PARSE_CONFIG_PRAGMA_PATH) as { + parseConfigPragmaForTests: typeof ParseConfigPragma; }; // only try logging if we filtered out all but one fixture, @@ -75,7 +75,7 @@ async function compile( const result = await transformFixtureInput( input, fixturePath, - parseConfigPragma, + parseConfigPragmaForTests, BabelPluginReactCompiler, includeEvaluator, EffectEnum, From f2f002c7c19e273f3f31289d6f288c3248f10183 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:26:50 -0500 Subject: [PATCH 347/426] [compiler][be] Stabilize compiler output: sort deps and decls by name (#31362) All dependencies and declarations of a reactive scope can be reordered to scope start/end. i.e. generated code does not depend on conditional short-circuiting logic as dependencies are inferred to have no side effects. Sorting these by name helps us get higher signal compilation snapshot diffs when upgrading the compiler and testing PRs --- .../ReactiveScopes/CodegenReactiveFunction.ts | 51 ++++++++++++++++++- ...ng-primitive-as-dep-nested-scope.expect.md | 6 +-- .../compiler/array-at-effect.expect.md | 6 +-- .../array-expression-spread.expect.md | 6 +-- .../compiler/array-property-call.expect.md | 10 ++-- .../bug-invalid-phi-as-dependency.expect.md | 6 +-- ...nstruction-hoisted-sequence-expr.expect.md | 10 ++-- ...fun-alias-captured-mutate-2-iife.expect.md | 6 +-- ...ring-fun-alias-captured-mutate-2.expect.md | 6 +-- ...alias-captured-mutate-arr-2-iife.expect.md | 6 +-- ...-fun-alias-captured-mutate-arr-2.expect.md | 6 +-- ...c-alias-captured-mutate-arr-iife.expect.md | 6 +-- ...g-func-alias-captured-mutate-arr.expect.md | 6 +-- ...-func-alias-captured-mutate-iife.expect.md | 6 +-- ...uring-func-alias-captured-mutate.expect.md | 6 +-- ...turing-function-member-expr-call.expect.md | 6 +-- .../fixtures/compiler/component.expect.md | 12 ++--- .../compiler/computed-call-spread.expect.md | 8 +-- .../compiler/dependencies-outputs.expect.md | 6 +-- .../destructure-in-branch-ssa.expect.md | 8 +-- ...g-same-property-identifier-names.expect.md | 6 +-- .../fixtures/compiler/destructuring.expect.md | 34 ++++++------- ...er-declaration-of-previous-scope.expect.md | 10 ++-- .../existing-variables-with-c-name.expect.md | 6 +-- .../compiler/fast-refresh-reloading.expect.md | 6 +-- ...-mutable-range-destructured-prop.expect.md | 6 +-- ...btparam-with-jsx-element-content.expect.md | 6 +-- ...oop-with-value-block-initializer.expect.md | 6 +-- ...onmutating-loop-local-collection.expect.md | 6 +-- ...pression-prototype-call-mutating.expect.md | 6 +-- ...unctionexpr-conditional-access-2.expect.md | 6 +-- ...r\342\200\223conditional-access.expect.md" | 6 +-- ...bals-dont-resolve-local-useState.expect.md | 6 +-- .../fixtures/compiler/hook-noAlias.expect.md | 6 +-- .../compiler/hooks-with-prefix.expect.md | 6 +-- ...incompatible-destructuring-kinds.expect.md | 14 ++--- ...-promoted-to-outer-scope-dynamic.expect.md | 20 ++++---- ...jsx-outlining-child-stored-in-id.expect.md | 12 ++--- .../jsx-outlining-jsx-stored-in-id.expect.md | 18 +++---- .../jsx-outlining-separate-nested.expect.md | 22 ++++---- .../compiler/jsx-outlining-simple.expect.md | 18 +++---- ...-tag-evaluation-order-non-global.expect.md | 16 +++--- .../lambda-capture-returned-alias.expect.md | 6 +-- .../lower-context-acess-multiple.expect.md | 6 +-- .../lower-context-selector-simple.expect.md | 6 +-- ...ge-consecutive-scopes-reordering.expect.md | 6 +-- .../compiler/method-call-computed.expect.md | 8 +-- .../compiler/method-call-fn-call.expect.md | 8 +-- .../fixtures/compiler/method-call.expect.md | 6 +-- ...pture-in-unsplittable-memo-block.expect.md | 10 ++-- .../object-shorthand-method-nested.expect.md | 6 +-- ...al-member-expression-as-memo-dep.expect.md | 6 +-- ...ession-single-with-unconditional.expect.md | 6 +-- ...ptional-member-expression-single.expect.md | 6 +-- ...ession-with-conditional-optional.expect.md | 12 ++--- ...mber-expression-with-conditional.expect.md | 12 ++--- ...rly-return-within-reactive-scope.expect.md | 10 ++-- ...Callback-in-other-reactive-block.expect.md | 8 +-- ...k-reordering-deplist-controlflow.expect.md | 16 +++--- ...useMemo-conditional-access-alloc.expect.md | 6 +-- ...eMemo-conditional-access-noAlloc.expect.md | 6 +-- .../useMemo-in-other-reactive-block.expect.md | 8 +-- ...-reordering-depslist-controlflow.expect.md | 6 +-- .../primitive-as-dep-nested-scope.expect.md | 6 +-- ...signed-loop-force-scopes-enabled.expect.md | 8 +-- ...rly-return-within-reactive-scope.expect.md | 8 +-- ...rly-return-within-reactive-scope.expect.md | 8 +-- .../iife-return-modified-later-phi.expect.md | 6 +-- ...al-member-expression-as-memo-dep.expect.md | 6 +-- ...ession-single-with-unconditional.expect.md | 6 +-- ...ptional-member-expression-single.expect.md | 6 +-- ...rly-return-within-reactive-scope.expect.md | 18 +++---- ...hi-type-inference-property-store.expect.md | 6 +-- ...r-function-cond-access-local-var.expect.md | 6 +-- ...function-cond-access-not-hoisted.expect.md | 6 +-- ...n-uncond-access-hoists-other-dep.expect.md | 6 +-- ...uncond-optional-hoists-other-dep.expect.md | 12 ++--- .../infer-objectmethod-cond-access.expect.md | 6 +-- .../memberexpr-join-optional-chain2.expect.md | 6 +-- .../promote-uncond.expect.md | 8 +-- ...a-renaming-unconditional-ternary.expect.md | 8 +-- .../switch-non-final-default.expect.md | 16 +++--- .../switch.expect.md | 16 +++--- ...value-modified-in-catch-escaping.expect.md | 6 +-- ...atch-try-value-modified-in-catch.expect.md | 6 +-- .../useMemo-multiple-if-else.expect.md | 16 +++--- ...-analysis-interleaved-reactivity.expect.md | 6 +-- ...ve-via-mutation-of-computed-load.expect.md | 12 ++--- ...ve-via-mutation-of-property-load.expect.md | 6 +-- .../reassignment-separate-scopes.expect.md | 16 +++--- ...eactive-cond-deps-break-in-scope.expect.md | 6 +-- ...active-cond-deps-return-in-scope.expect.md | 16 +++--- ...function-cond-access-not-hoisted.expect.md | 6 +-- .../hoist-deps-diff-ssa-instance.expect.md | 6 +-- .../jump-poisoned/break-in-scope.expect.md | 6 +-- .../loop-break-in-scope.expect.md | 6 +-- ...e-if-nonexhaustive-poisoned-deps.expect.md | 10 ++-- ...-if-nonexhaustive-poisoned-deps1.expect.md | 10 ++-- .../jump-poisoned/return-in-scope.expect.md | 16 +++--- .../return-poisons-outer-scope.expect.md | 10 ++-- ...p-target-within-scope-loop-break.expect.md | 6 +-- ...e-if-exhaustive-nonpoisoned-deps.expect.md | 10 ++-- ...-if-exhaustive-nonpoisoned-deps1.expect.md | 10 ++-- .../memberexpr-join-optional-chain2.expect.md | 6 +-- .../promote-uncond.expect.md | 6 +-- ...duce-if-exhaustive-poisoned-deps.expect.md | 18 +++---- .../subpath-order1.expect.md | 6 +-- .../superpath-order1.expect.md | 6 +-- .../uncond-access-in-mutable-range.expect.md | 6 +-- .../uncond-nonoverlap-descendant.expect.md | 6 +-- .../reordering-across-blocks.expect.md | 6 +-- ...ed-property-load-for-method-call.expect.md | 6 +-- ...uned-scope-leaks-value-via-alias.expect.md | 6 +-- ...invalid-pruned-scope-leaks-value.expect.md | 6 +-- ...o-invalid-reactivity-value-block.expect.md | 6 +-- ...lack-of-phi-types-explicit-types.expect.md | 6 +-- ...ng-memoization-lack-of-phi-types.expect.md | 6 +-- .../repro-no-value-for-temporary.expect.md | 6 +-- ...ro-propagate-type-of-ternary-jsx.expect.md | 8 +-- ...epro-slow-validate-preserve-memo.expect.md | 6 +-- ...erge-overlapping-reactive-scopes.expect.md | 6 +-- ...ble-code-early-return-in-useMemo.expect.md | 6 +-- .../fixtures/compiler/repro.expect.md | 10 ++-- .../rest-param-with-array-pattern.expect.md | 6 +-- .../rest-param-with-identifier.expect.md | 6 +-- ...param-with-object-spread-pattern.expect.md | 6 +-- ...s-dep-and-redeclare-maybe-frozen.expect.md | 14 ++--- ...me-variable-as-dep-and-redeclare.expect.md | 24 ++++----- ...assignment-to-scope-declarations.expect.md | 14 ++--- ...ixed-local-and-scope-declaration.expect.md | 14 ++--- .../switch-non-final-default.expect.md | 16 +++--- .../fixtures/compiler/switch.expect.md | 16 +++--- .../todo.jsx-outlining-children.expect.md | 12 ++--- ...odo.jsx-outlining-duplicate-prop.expect.md | 12 ++--- ...ntext-access-array-destructuring.expect.md | 6 +-- ...text-access-destructure-multiple.expect.md | 6 +-- ...r-context-access-mixed-array-obj.expect.md | 6 +-- ...text-access-nested-destructuring.expect.md | 6 +-- ...wer-context-access-property-load.expect.md | 6 +-- .../try-catch-in-nested-scope.expect.md | 16 +++--- ...value-modified-in-catch-escaping.expect.md | 6 +-- ...atch-try-value-modified-in-catch.expect.md | 6 +-- .../try-catch-with-catch-param.expect.md | 10 ++-- .../compiler/try-catch-with-return.expect.md | 10 ++-- ...type-provider-log-default-import.expect.md | 12 ++--- .../compiler/type-provider-log.expect.md | 12 ++--- ...r-store-capture-namespace-import.expect.md | 20 ++++---- .../type-provider-store-capture.expect.md | 20 ++++---- .../fixtures/compiler/unary-expr.expect.md | 24 ++++----- .../use-operator-call-expression.expect.md | 6 +-- .../use-operator-conditional.expect.md | 6 +-- .../use-operator-method-call.expect.md | 6 +-- .../useEffect-nested-lambdas.expect.md | 6 +-- .../useState-unpruned-dependency.expect.md | 6 +-- 154 files changed, 732 insertions(+), 685 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts index 297c7712546c9..167db6dedeccc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -34,6 +34,7 @@ import { ReactiveInstruction, ReactiveScope, ReactiveScopeBlock, + ReactiveScopeDeclaration, ReactiveScopeDependency, ReactiveTerminal, ReactiveValue, @@ -572,7 +573,8 @@ function codegenReactiveScope( const changeExpressions: Array = []; const changeExpressionComments: Array = []; const outputComments: Array = []; - for (const dep of scope.dependencies) { + + for (const dep of [...scope.dependencies].sort(compareScopeDependency)) { const index = cx.nextCacheIndex; changeExpressionComments.push(printDependencyComment(dep)); const comparison = t.binaryExpression( @@ -615,7 +617,10 @@ function codegenReactiveScope( ); } let firstOutputIndex: number | null = null; - for (const [, {identifier}] of scope.declarations) { + + for (const [, {identifier}] of [...scope.declarations].sort(([, a], [, b]) => + compareScopeDeclaration(a, b), + )) { const index = cx.nextCacheIndex; if (firstOutputIndex === null) { firstOutputIndex = index; @@ -2566,3 +2571,45 @@ function convertIdentifier(identifier: Identifier): t.Identifier { ); return t.identifier(identifier.name.value); } + +function compareScopeDependency( + a: ReactiveScopeDependency, + b: ReactiveScopeDependency, +): number { + CompilerError.invariant( + a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named', + { + reason: '[Codegen] Expected named identifier for dependency', + loc: a.identifier.loc, + }, + ); + const aName = [ + a.identifier.name.value, + ...a.path.map(entry => `${entry.optional ? '?' : ''}${entry.property}`), + ].join('.'); + const bName = [ + b.identifier.name.value, + ...b.path.map(entry => `${entry.optional ? '?' : ''}${entry.property}`), + ].join('.'); + if (aName < bName) return -1; + else if (aName > bName) return 1; + else return 0; +} + +function compareScopeDeclaration( + a: ReactiveScopeDeclaration, + b: ReactiveScopeDeclaration, +): number { + CompilerError.invariant( + a.identifier.name?.kind === 'named' && b.identifier.name?.kind === 'named', + { + reason: '[Codegen] Expected named identifier for declaration', + loc: a.identifier.loc, + }, + ); + const aName = a.identifier.name.value; + const bName = b.identifier.name.value; + if (aName < bName) return -1; + else if (aName > bName) return 1; + else return 0; +} diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allocating-primitive-as-dep-nested-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allocating-primitive-as-dep-nested-scope.expect.md index cb550b42302c2..6702b26e92dbc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allocating-primitive-as-dep-nested-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/allocating-primitive-as-dep-nested-scope.expect.md @@ -47,7 +47,7 @@ import { identity, mutate, setProperty } from "shared-runtime"; function AllocatingPrimitiveAsDepNested(props) { const $ = _c(5); let t0; - if ($[0] !== props.b || $[1] !== props.a) { + if ($[0] !== props.a || $[1] !== props.b) { const x = {}; mutate(x); const t1 = identity(props.b) + 1; @@ -62,8 +62,8 @@ function AllocatingPrimitiveAsDepNested(props) { const y = t2; setProperty(x, props.a); t0 = [x, y]; - $[0] = props.b; - $[1] = props.a; + $[0] = props.a; + $[1] = props.b; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-effect.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-effect.expect.md index 3aa51ba6d6f3b..a8bad51215473 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-effect.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-at-effect.expect.md @@ -41,7 +41,7 @@ function ArrayAtTest(props) { } const arr = t1; let t2; - if ($[4] !== props.y || $[5] !== arr) { + if ($[4] !== arr || $[5] !== props.y) { let t3; if ($[7] !== props.y) { t3 = bar(props.y); @@ -51,8 +51,8 @@ function ArrayAtTest(props) { t3 = $[8]; } t2 = arr.at(t3); - $[4] = props.y; - $[5] = arr; + $[4] = arr; + $[5] = props.y; $[6] = t2; } else { t2 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-expression-spread.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-expression-spread.expect.md index 46ae9492389af..f3af7efcf62e7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-expression-spread.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-expression-spread.expect.md @@ -22,10 +22,10 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(3); let t0; - if ($[0] !== props.foo || $[1] !== props.bar) { + if ($[0] !== props.bar || $[1] !== props.foo) { t0 = [0, ...props.foo, null, ...props.bar, "z"]; - $[0] = props.foo; - $[1] = props.bar; + $[0] = props.bar; + $[1] = props.foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-property-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-property-call.expect.md index 7aa47c5803a22..6618be4a6c04c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-property-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/array-property-call.expect.md @@ -24,18 +24,18 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(11); - let t0; let a; + let t0; if ($[0] !== props.a || $[1] !== props.b) { a = [props.a, props.b, "hello"]; t0 = a.push(42); $[0] = props.a; $[1] = props.b; - $[2] = t0; - $[3] = a; + $[2] = a; + $[3] = t0; } else { - t0 = $[2]; - a = $[3]; + a = $[2]; + t0 = $[3]; } const x = t0; let t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md index 32e2c9fd6483e..09d2d8800b789 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-phi-as-dependency.expect.md @@ -70,10 +70,10 @@ function Component() { throw new Error("invariant broken"); } let t1; - if ($[1] !== obj || $[2] !== boxedInner) { + if ($[1] !== boxedInner || $[2] !== obj) { t1 = ; - $[1] = obj; - $[2] = boxedInner; + $[1] = boxedInner; + $[2] = obj; $[3] = t1; } else { t1 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md index dcca6cddd8fb2..4ffe0fcb6a541 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr.expect.md @@ -57,16 +57,16 @@ import { identity, mutate } from "shared-runtime"; */ function Component(props) { const $ = _c(8); - let t0; let key; + let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { key = {}; t0 = (mutate(key), key); - $[0] = t0; - $[1] = key; + $[0] = key; + $[1] = t0; } else { - t0 = $[0]; - key = $[1]; + key = $[0]; + t0 = $[1]; } const tmp = t0; let t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2-iife.expect.md index 65ab9c277c2d1..5e0b32709b32e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2-iife.expect.md @@ -32,7 +32,7 @@ import { mutate } from "shared-runtime"; function component(foo, bar) { const $ = _c(3); let x; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { x = { foo }; const y = { bar }; @@ -41,8 +41,8 @@ function component(foo, bar) { a.x = b; mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2.expect.md index 170f68badeffe..f9ce3f2e98cf5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-2.expect.md @@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime"; function component(foo, bar) { const $ = _c(3); let x; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { x = { foo }; const y = { bar }; const f0 = function () { @@ -35,8 +35,8 @@ function component(foo, bar) { f0(); mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2-iife.expect.md index e315cd401d433..81737a1ed500f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2-iife.expect.md @@ -32,7 +32,7 @@ const { mutate } = require("shared-runtime"); function component(foo, bar) { const $ = _c(3); let x; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { x = { foo }; const y = { bar }; @@ -41,8 +41,8 @@ function component(foo, bar) { a.x = b; mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2.expect.md index 7371f3d27a29d..38590d1559bb5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-fun-alias-captured-mutate-arr-2.expect.md @@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime"; function component(foo, bar) { const $ = _c(3); let x; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { x = { foo }; const y = { bar }; const f0 = function () { @@ -35,8 +35,8 @@ function component(foo, bar) { f0(); mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr-iife.expect.md index cc41adcbbcff9..4882aa822f430 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr-iife.expect.md @@ -32,7 +32,7 @@ const { mutate } = require("shared-runtime"); function component(foo, bar) { const $ = _c(3); let y; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { const x = { foo }; y = { bar }; @@ -41,8 +41,8 @@ function component(foo, bar) { a.x = b; mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = y; } else { y = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr.expect.md index 34f6a55740c31..7c94c33e495a8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-arr.expect.md @@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime"; function component(foo, bar) { const $ = _c(3); let y; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { const x = { foo }; y = { bar }; const f0 = function () { @@ -35,8 +35,8 @@ function component(foo, bar) { f0(); mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = y; } else { y = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-iife.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-iife.expect.md index b2d704875631e..60493dd25ad74 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-iife.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate-iife.expect.md @@ -32,7 +32,7 @@ const { mutate } = require("shared-runtime"); function component(foo, bar) { const $ = _c(3); let y; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { const x = { foo }; y = { bar }; @@ -41,8 +41,8 @@ function component(foo, bar) { a.x = b; mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = y; } else { y = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate.expect.md index a68e919c9678f..14532562fb153 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-alias-captured-mutate.expect.md @@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime"; function component(foo, bar) { const $ = _c(3); let y; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { const x = { foo }; y = { bar }; const f0 = function () { @@ -35,8 +35,8 @@ function component(foo, bar) { f0(); mutate(y); - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = y; } else { y = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-member-expr-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-member-expr-call.expect.md index 51679299fee72..cab9c9a500b9c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-member-expr-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-function-member-expr-call.expect.md @@ -46,10 +46,10 @@ function component(t0) { } const hide = t2; let t3; - if ($[4] !== poke || $[5] !== hide) { + if ($[4] !== hide || $[5] !== poke) { t3 = ; - $[4] = poke; - $[5] = hide; + $[4] = hide; + $[5] = poke; $[6] = t3; } else { t3 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/component.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/component.expect.md index 80d6e6df8c086..c6037fd2bb390 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/component.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/component.expect.md @@ -46,7 +46,7 @@ function Component(props) { const items = props.items; const maxItems = props.maxItems; let renderedItems; - if ($[0] !== maxItems || $[1] !== items) { + if ($[0] !== items || $[1] !== maxItems) { renderedItems = []; const seen = new Set(); const max = Math.max(0, maxItems); @@ -62,8 +62,8 @@ function Component(props) { break; } } - $[0] = maxItems; - $[1] = items; + $[0] = items; + $[1] = maxItems; $[2] = renderedItems; } else { renderedItems = $[2]; @@ -79,15 +79,15 @@ function Component(props) { t0 = $[4]; } let t1; - if ($[5] !== t0 || $[6] !== renderedItems) { + if ($[5] !== renderedItems || $[6] !== t0) { t1 = (
{t0} {renderedItems}
); - $[5] = t0; - $[6] = renderedItems; + $[5] = renderedItems; + $[6] = t0; $[7] = t1; } else { t1 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/computed-call-spread.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/computed-call-spread.expect.md index cb20d97cb7c49..0329450b13e34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/computed-call-spread.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/computed-call-spread.expect.md @@ -16,11 +16,11 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(4); let t0; - if ($[0] !== props.method || $[1] !== props.a || $[2] !== props.b) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.method) { t0 = foo[props.method](...props.a, null, ...props.b); - $[0] = props.method; - $[1] = props.a; - $[2] = props.b; + $[0] = props.a; + $[1] = props.b; + $[2] = props.method; $[3] = t0; } else { t0 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md index 6fc686cb197fc..f0f9911c07e92 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dependencies-outputs.expect.md @@ -41,7 +41,7 @@ function foo(a, b) { x = $[1]; } let y; - if ($[2] !== x || $[3] !== b) { + if ($[2] !== b || $[3] !== x) { y = []; if (x.length) { y.push(x); @@ -49,8 +49,8 @@ function foo(a, b) { if (b) { y.push(b); } - $[2] = x; - $[3] = b; + $[2] = b; + $[3] = x; $[4] = y; } else { y = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-in-branch-ssa.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-in-branch-ssa.expect.md index d65082cbc87c7..b159789106267 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-in-branch-ssa.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructure-in-branch-ssa.expect.md @@ -61,11 +61,11 @@ function useFoo(props) { z = $[4]; } let t0; - if ($[5] !== x || $[6] !== y || $[7] !== myList) { + if ($[5] !== myList || $[6] !== x || $[7] !== y) { t0 = { x, y, myList }; - $[5] = x; - $[6] = y; - $[7] = myList; + $[5] = myList; + $[6] = x; + $[7] = y; $[8] = t0; } else { t0 = $[8]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-same-property-identifier-names.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-same-property-identifier-names.expect.md index b86498b922d38..3e1c4771eabfb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-same-property-identifier-names.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring-same-property-identifier-names.expect.md @@ -41,10 +41,10 @@ function Component(props) { } const sameName = t1; let t2; - if ($[2] !== sameName || $[3] !== renamed) { + if ($[2] !== renamed || $[3] !== sameName) { t2 = [sameName, renamed]; - $[2] = sameName; - $[3] = renamed; + $[2] = renamed; + $[3] = sameName; $[4] = t2; } else { t2 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring.expect.md index c175cc558cf06..f292e83e16438 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/destructuring.expect.md @@ -36,45 +36,45 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function foo(a, b, c) { const $ = _c(18); - let t0; let d; let h; + let t0; if ($[0] !== a) { [d, t0, ...h] = a; $[0] = a; - $[1] = t0; - $[2] = d; - $[3] = h; + $[1] = d; + $[2] = h; + $[3] = t0; } else { - t0 = $[1]; - d = $[2]; - h = $[3]; + d = $[1]; + h = $[2]; + t0 = $[3]; } const [t1] = t0; - let t2; let g; + let t2; if ($[4] !== t1) { ({ e: t2, ...g } = t1); $[4] = t1; - $[5] = t2; - $[6] = g; + $[5] = g; + $[6] = t2; } else { - t2 = $[5]; - g = $[6]; + g = $[5]; + t2 = $[6]; } const { f } = t2; const { l: t3, p } = b; const { m: t4 } = t3; - let t5; let o; + let t5; if ($[7] !== t4) { [t5, ...o] = t4; $[7] = t4; - $[8] = t5; - $[9] = o; + $[8] = o; + $[9] = t5; } else { - t5 = $[8]; - o = $[9]; + o = $[8]; + t5 = $[9]; } const [n] = t5; let t6; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md index 29780eb76c2b6..ce5bfda64406b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/dont-merge-if-dep-is-inner-declaration-of-previous-scope.expect.md @@ -53,8 +53,8 @@ import { ValidateMemoization } from "shared-runtime"; function Component(t0) { const $ = _c(25); const { a, b, c } = t0; - let y; let x; + let y; if ($[0] !== a || $[1] !== b || $[2] !== c) { x = []; if (a) { @@ -73,11 +73,11 @@ function Component(t0) { $[0] = a; $[1] = b; $[2] = c; - $[3] = y; - $[4] = x; + $[3] = x; + $[4] = y; } else { - y = $[3]; - x = $[4]; + x = $[3]; + y = $[4]; } let t1; if ($[7] !== y) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/existing-variables-with-c-name.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/existing-variables-with-c-name.expect.md index 0d671a3de2032..5cde3bde23cf1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/existing-variables-with-c-name.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/existing-variables-with-c-name.expect.md @@ -61,10 +61,10 @@ function Component(props) { t2 = $[3]; } let t3; - if ($[4] !== t2 || $[5] !== array) { + if ($[4] !== array || $[5] !== t2) { t3 = ; - $[4] = t2; - $[5] = array; + $[4] = array; + $[5] = t2; $[6] = t3; } else { t3 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fast-refresh-reloading.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fast-refresh-reloading.expect.md index ecd03a0b10231..4175d23fdab57 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fast-refresh-reloading.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fast-refresh-reloading.expect.md @@ -59,10 +59,10 @@ function Component(props) { t3 = $[4]; } let t4; - if ($[5] !== t3 || $[6] !== doubled) { + if ($[5] !== doubled || $[6] !== t3) { t4 = ; - $[5] = t3; - $[6] = doubled; + $[5] = doubled; + $[6] = t3; $[7] = t4; } else { t4 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-repro-invalid-mutable-range-destructured-prop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-repro-invalid-mutable-range-destructured-prop.expect.md index d56f7a98ad1ad..9bb651aa676e6 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-repro-invalid-mutable-range-destructured-prop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbt-repro-invalid-mutable-range-destructured-prop.expect.md @@ -61,10 +61,10 @@ function Component(t0) { t3 = $[3]; } let t4; - if ($[4] !== t3 || $[5] !== el) { + if ($[4] !== el || $[5] !== t3) { t4 = ; - $[4] = t3; - $[5] = el; + $[4] = el; + $[5] = t3; $[6] = t4; } else { t4 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md index d58c25b51046a..56ffb70cb0aeb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/fbt/fbtparam-with-jsx-element-content.expect.md @@ -32,7 +32,7 @@ function Component(t0) { const $ = _c(4); const { name, data, icon } = t0; let t1; - if ($[0] !== name || $[1] !== icon || $[2] !== data) { + if ($[0] !== data || $[1] !== icon || $[2] !== name) { t1 = ( {fbt._( @@ -61,9 +61,9 @@ function Component(t0) { )} ); - $[0] = name; + $[0] = data; $[1] = icon; - $[2] = data; + $[2] = name; $[3] = t1; } else { t1 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-value-block-initializer.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-value-block-initializer.expect.md index 24f2e545ccc5a..6ef73de8b04f9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-value-block-initializer.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-loop-with-value-block-initializer.expect.md @@ -67,7 +67,7 @@ const TOTAL = 10; function Component(props) { const $ = _c(3); let t0; - if ($[0] !== props.start || $[1] !== props.items) { + if ($[0] !== props.items || $[1] !== props.start) { const items = []; for (let i = props.start ?? 0; i < props.items.length; i++) { const item = props.items[i]; @@ -75,8 +75,8 @@ function Component(props) { } t0 =
{items}
; - $[0] = props.start; - $[1] = props.items; + $[0] = props.items; + $[1] = props.start; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-nonmutating-loop-local-collection.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-nonmutating-loop-local-collection.expect.md index cff8c5bd13cfa..4abe630044084 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-nonmutating-loop-local-collection.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/for-of-nonmutating-loop-local-collection.expect.md @@ -91,10 +91,10 @@ function Component(t0) { t5 = $[9]; } let t6; - if ($[10] !== x || $[11] !== b) { + if ($[10] !== b || $[11] !== x) { t6 = [x, b]; - $[10] = x; - $[11] = b; + $[10] = b; + $[11] = x; $[12] = t6; } else { t6 = $[12]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call-mutating.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call-mutating.expect.md index be59673c157e0..9888e96222b3d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call-mutating.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/function-expression-prototype-call-mutating.expect.md @@ -59,10 +59,10 @@ function Component(props) { t1 = $[3]; } let t2; - if ($[4] !== t1 || $[5] !== a_0) { + if ($[4] !== a_0 || $[5] !== t1) { t2 = ; - $[4] = t1; - $[5] = a_0; + $[4] = a_0; + $[5] = t1; $[6] = t2; } else { t2 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md index 8cbaeb3f89465..32498e1379206 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md @@ -36,10 +36,10 @@ function Component(t0) { } const f = t1; let t2; - if ($[2] !== props || $[3] !== f) { + if ($[2] !== f || $[3] !== props) { t2 = props == null ? _temp : f; - $[2] = props; - $[3] = f; + $[2] = f; + $[3] = props; $[4] = t2; } else { t2 = $[4]; diff --git "a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" "b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" index f2fa20feb5477..4a62bf6f249bb 100644 --- "a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" +++ "b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" @@ -36,10 +36,10 @@ function Component(props) { } const getLength = t0; let t1; - if ($[2] !== props.bar || $[3] !== getLength) { + if ($[2] !== getLength || $[3] !== props.bar) { t1 = props.bar && getLength(); - $[2] = props.bar; - $[3] = getLength; + $[2] = getLength; + $[3] = props.bar; $[4] = t1; } else { t1 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/globals-dont-resolve-local-useState.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/globals-dont-resolve-local-useState.expect.md index 7548a3b6392f5..be7f3f1bd28d8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/globals-dont-resolve-local-useState.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/globals-dont-resolve-local-useState.expect.md @@ -56,10 +56,10 @@ function Component() { t0 = $[1]; } let t1; - if ($[2] !== t0 || $[3] !== state) { + if ($[2] !== state || $[3] !== t0) { t1 =
{state}
; - $[2] = t0; - $[3] = state; + $[2] = state; + $[3] = t0; $[4] = t1; } else { t1 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-noAlias.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-noAlias.expect.md index 96ccd1e2f1c20..329d57a035192 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-noAlias.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hook-noAlias.expect.md @@ -41,10 +41,10 @@ function Component(props) { console.log(props); }, [props.a]); let t1; - if ($[2] !== x || $[3] !== item) { + if ($[2] !== item || $[3] !== x) { t1 = [x, item]; - $[2] = x; - $[3] = item; + $[2] = item; + $[3] = x; $[4] = t1; } else { t1 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hooks-with-prefix.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hooks-with-prefix.expect.md index f7e02a53f161a..085df625f5544 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hooks-with-prefix.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hooks-with-prefix.expect.md @@ -73,15 +73,15 @@ function Component() { t1 = $[4]; } let t3; - if ($[5] !== t2 || $[6] !== json) { + if ($[5] !== json || $[6] !== t2) { t3 = (
{t2} {json}
); - $[5] = t2; - $[6] = json; + $[5] = json; + $[6] = t2; $[7] = t3; } else { t3 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/incompatible-destructuring-kinds.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/incompatible-destructuring-kinds.expect.md index 970cc50f03f27..8afc59a80ba02 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/incompatible-destructuring-kinds.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/incompatible-destructuring-kinds.expect.md @@ -29,22 +29,22 @@ import { Stringify } from "shared-runtime"; function Component(t0) { const $ = _c(4); - let t1; let a; let b; + let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { a = "a"; const [t2, t3] = [null, null]; t1 = t3; a = t2; - $[0] = t1; - $[1] = a; - $[2] = b; + $[0] = a; + $[1] = b; + $[2] = t1; } else { - t1 = $[0]; - a = $[1]; - b = $[2]; + a = $[0]; + b = $[1]; + t1 = $[2]; } b = t1; let t2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md index becc4066e7d76..735462657f93e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inner-memo-value-not-promoted-to-outer-scope-dynamic.expect.md @@ -27,10 +27,10 @@ function Component(props) { const $ = _c(15); const item = useFragment(FRAGMENT, props.item); useFreeze(item); - let t0; let T0; - let t1; let T1; + let t0; + let t1; if ($[0] !== item) { const count = new MaybeMutable(item); @@ -44,15 +44,15 @@ function Component(props) { } t0 = maybeMutate(count); $[0] = item; - $[1] = t0; - $[2] = T0; - $[3] = t1; - $[4] = T1; + $[1] = T0; + $[2] = T1; + $[3] = t0; + $[4] = t1; } else { - t0 = $[1]; - T0 = $[2]; - t1 = $[3]; - T1 = $[4]; + T0 = $[1]; + T1 = $[2]; + t0 = $[3]; + t1 = $[4]; } let t2; if ($[6] !== t0) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md index fd7ca41bcffa3..b84229156bc14 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-child-stored-in-id.expect.md @@ -83,10 +83,10 @@ function _temp(t0) { t1 = $[1]; } let t2; - if ($[2] !== x || $[3] !== t1) { + if ($[2] !== t1 || $[3] !== x) { t2 = {t1}; - $[2] = x; - $[3] = t1; + $[2] = t1; + $[3] = x; $[4] = t2; } else { t2 = $[4]; @@ -98,15 +98,15 @@ function Bar(t0) { const $ = _c(3); const { x, children } = t0; let t1; - if ($[0] !== x || $[1] !== children) { + if ($[0] !== children || $[1] !== x) { t1 = ( <> {x} {children} ); - $[0] = x; - $[1] = children; + $[0] = children; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md index 496282e1ef611..7fca963134b71 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-jsx-stored-in-id.expect.md @@ -52,7 +52,7 @@ function Component(t0) { const { arr } = t0; const x = useX(); let t1; - if ($[0] !== x || $[1] !== arr) { + if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { t2 = (i, id) => { @@ -66,8 +66,8 @@ function Component(t0) { t2 = $[4]; } t1 = arr.map(t2); - $[0] = x; - $[1] = arr; + $[0] = arr; + $[1] = x; $[2] = t1; } else { t1 = $[2]; @@ -94,10 +94,10 @@ function _temp(t0) { t1 = $[1]; } let t2; - if ($[2] !== x || $[3] !== t1) { + if ($[2] !== t1 || $[3] !== x) { t2 = {t1}; - $[2] = x; - $[3] = t1; + $[2] = t1; + $[3] = x; $[4] = t2; } else { t2 = $[4]; @@ -109,15 +109,15 @@ function Bar(t0) { const $ = _c(3); const { x, children } = t0; let t1; - if ($[0] !== x || $[1] !== children) { + if ($[0] !== children || $[1] !== x) { t1 = ( <> {x} {children} ); - $[0] = x; - $[1] = children; + $[0] = children; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md index 7f86546cd4d19..9d2b254c063d7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-separate-nested.expect.md @@ -60,7 +60,7 @@ function Component(t0) { const { arr } = t0; const x = useX(); let t1; - if ($[0] !== x || $[1] !== arr) { + if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { t2 = (i, id) => { @@ -73,8 +73,8 @@ function Component(t0) { t2 = $[4]; } t1 = arr.map(t2); - $[0] = x; - $[1] = arr; + $[0] = arr; + $[1] = x; $[2] = t1; } else { t1 = $[2]; @@ -117,7 +117,7 @@ function _temp(t0) { t3 = $[5]; } let t4; - if ($[6] !== x || $[7] !== t1 || $[8] !== t2 || $[9] !== t3) { + if ($[6] !== t1 || $[7] !== t2 || $[8] !== t3 || $[9] !== x) { t4 = ( {t1} @@ -125,10 +125,10 @@ function _temp(t0) { {t3} ); - $[6] = x; - $[7] = t1; - $[8] = t2; - $[9] = t3; + $[6] = t1; + $[7] = t2; + $[8] = t3; + $[9] = x; $[10] = t4; } else { t4 = $[10]; @@ -140,15 +140,15 @@ function Bar(t0) { const $ = _c(3); const { x, children } = t0; let t1; - if ($[0] !== x || $[1] !== children) { + if ($[0] !== children || $[1] !== x) { t1 = ( <> {x} {children} ); - $[0] = x; - $[1] = children; + $[0] = children; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md index 9e268227a2383..09323f5ac65e1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-simple.expect.md @@ -50,7 +50,7 @@ function Component(t0) { const { arr } = t0; const x = useX(); let t1; - if ($[0] !== x || $[1] !== arr) { + if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { t2 = (i, id) => { @@ -63,8 +63,8 @@ function Component(t0) { t2 = $[4]; } t1 = arr.map(t2); - $[0] = x; - $[1] = arr; + $[0] = arr; + $[1] = x; $[2] = t1; } else { t1 = $[2]; @@ -91,10 +91,10 @@ function _temp(t0) { t1 = $[1]; } let t2; - if ($[2] !== x || $[3] !== t1) { + if ($[2] !== t1 || $[3] !== x) { t2 = {t1}; - $[2] = x; - $[3] = t1; + $[2] = t1; + $[3] = x; $[4] = t2; } else { t2 = $[4]; @@ -106,15 +106,15 @@ function Bar(t0) { const $ = _c(3); const { x, children } = t0; let t1; - if ($[0] !== x || $[1] !== children) { + if ($[0] !== children || $[1] !== x) { t1 = ( <> {x} {children} ); - $[0] = x; - $[1] = children; + $[0] = children; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-tag-evaluation-order-non-global.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-tag-evaluation-order-non-global.expect.md index b1dfbc61c39fc..d46ce53bb03bc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-tag-evaluation-order-non-global.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-tag-evaluation-order-non-global.expect.md @@ -53,23 +53,23 @@ function maybeMutate(x) {} function Component(props) { const $ = _c(11); - let Tag; let T0; + let Tag; let t0; - if ($[0] !== props.component || $[1] !== props.alternateComponent) { + if ($[0] !== props.alternateComponent || $[1] !== props.component) { const maybeMutable = new MaybeMutable(); Tag = props.component; T0 = Tag; t0 = ((Tag = props.alternateComponent), maybeMutate(maybeMutable)); - $[0] = props.component; - $[1] = props.alternateComponent; - $[2] = Tag; - $[3] = T0; + $[0] = props.alternateComponent; + $[1] = props.component; + $[2] = T0; + $[3] = Tag; $[4] = t0; } else { - Tag = $[2]; - T0 = $[3]; + T0 = $[2]; + Tag = $[3]; t0 = $[4]; } let t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-capture-returned-alias.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-capture-returned-alias.expect.md index e172ee1039343..bac21217c75f3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-capture-returned-alias.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lambda-capture-returned-alias.expect.md @@ -44,7 +44,7 @@ function CaptureNotMutate(props) { } const idx = t0; let aliasedElement; - if ($[2] !== props.el || $[3] !== idx) { + if ($[2] !== idx || $[3] !== props.el) { const element = bar(props.el); const fn = function () { @@ -54,8 +54,8 @@ function CaptureNotMutate(props) { aliasedElement = fn(); mutate(aliasedElement); - $[2] = props.el; - $[3] = idx; + $[2] = idx; + $[3] = props.el; $[4] = aliasedElement; } else { aliasedElement = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md index 47c7a2d74327b..af9b1df36ad01 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-acess-multiple.expect.md @@ -21,10 +21,10 @@ function App() { const { foo } = useContext_withSelector(MyContext, _temp); const { bar } = useContext_withSelector(MyContext, _temp2); let t0; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t0 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md index 0b12c2e250875..d13682467b3ed 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/lower-context-selector-simple.expect.md @@ -19,10 +19,10 @@ function App() { const $ = _c(3); const { foo, bar } = useContext_withSelector(MyContext, _temp); let t0; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t0 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-scopes-reordering.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-scopes-reordering.expect.md index 5bf1f2cf4d483..e5a9081137a20 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-scopes-reordering.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/merge-consecutive-scopes-reordering.expect.md @@ -60,7 +60,7 @@ function Component() { t2 = $[3]; } let t3; - if ($[4] !== t1 || $[5] !== t0) { + if ($[4] !== t0 || $[5] !== t1) { t3 = (
{t2} @@ -68,8 +68,8 @@ function Component() { {t0}
); - $[4] = t1; - $[5] = t0; + $[4] = t0; + $[5] = t1; $[6] = t3; } else { t3 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-computed.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-computed.expect.md index 887479c01eb01..2fc302c8b4287 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-computed.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-computed.expect.md @@ -43,11 +43,11 @@ function foo(a, b, c) { } const y = t1; let t2; - if ($[4] !== x || $[5] !== y.method || $[6] !== b) { + if ($[4] !== b || $[5] !== x || $[6] !== y.method) { t2 = x[y.method](b); - $[4] = x; - $[5] = y.method; - $[6] = b; + $[4] = b; + $[5] = x; + $[6] = y.method; $[7] = t2; } else { t2 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-fn-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-fn-call.expect.md index c32777534b8d4..58c06101d38eb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-fn-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call-fn-call.expect.md @@ -33,11 +33,11 @@ function foo(a, b, c) { const method = x.method; let t1; - if ($[2] !== method || $[3] !== x || $[4] !== b) { + if ($[2] !== b || $[3] !== method || $[4] !== x) { t1 = method.call(x, b); - $[2] = method; - $[3] = x; - $[4] = b; + $[2] = b; + $[3] = method; + $[4] = x; $[5] = t1; } else { t1 = $[5]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call.expect.md index ad45287d1ff5e..fd8a4935a8253 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/method-call.expect.md @@ -40,10 +40,10 @@ function foo(a, b, c) { } const x = t0; let t1; - if ($[2] !== x || $[3] !== b) { + if ($[2] !== b || $[3] !== x) { t1 = x.foo(b); - $[2] = x; - $[3] = b; + $[2] = b; + $[3] = x; $[4] = t1; } else { t1 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md index 090e9d889cfd9..a3403e6c8d812 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nonmutating-capture-in-unsplittable-memo-block.expect.md @@ -73,8 +73,8 @@ import { identity, mutate } from "shared-runtime"; function useFoo(t0) { const $ = _c(4); const { a, b } = t0; - let z; let y; + let z; if ($[0] !== a || $[1] !== b) { const x = { a }; y = {}; @@ -83,11 +83,11 @@ function useFoo(t0) { mutate(y); $[0] = a; $[1] = b; - $[2] = z; - $[3] = y; + $[2] = y; + $[3] = z; } else { - z = $[2]; - y = $[3]; + y = $[2]; + z = $[3]; } if (z[0] !== y) { throw new Error("oh no!"); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-shorthand-method-nested.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-shorthand-method-nested.expect.md index 4b500f52d6773..dc1cd699d295c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-shorthand-method-nested.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-shorthand-method-nested.expect.md @@ -40,7 +40,7 @@ function useHook(t0) { const { value } = t0; const [state] = useState(false); let t1; - if ($[0] !== value || $[1] !== state) { + if ($[0] !== state || $[1] !== value) { t1 = { getX() { return { @@ -52,8 +52,8 @@ function useHook(t0) { }; }, }; - $[0] = value; - $[1] = state; + $[0] = state; + $[1] = value; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md index 77875f789d7a8..3dd8e730325ea 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-as-memo-dep.expect.md @@ -63,10 +63,10 @@ function Component(t0) { t4 = $[3]; } let t5; - if ($[4] !== t4 || $[5] !== data) { + if ($[4] !== data || $[5] !== t4) { t5 = ; - $[4] = t4; - $[5] = data; + $[4] = data; + $[5] = t4; $[6] = t5; } else { t5 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md index 46767056bdcdf..3cd9877813c58 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single-with-unconditional.expect.md @@ -45,10 +45,10 @@ function Component(props) { t1 = $[3]; } let t2; - if ($[4] !== t1 || $[5] !== data) { + if ($[4] !== data || $[5] !== t1) { t2 = ; - $[4] = t1; - $[5] = data; + $[4] = data; + $[5] = t1; $[6] = t2; } else { t2 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md index 6e44a97b456b3..60a6171ab1ea1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-single.expect.md @@ -60,10 +60,10 @@ function Component(t0) { t3 = $[3]; } let t4; - if ($[4] !== t3 || $[5] !== data) { + if ($[4] !== data || $[5] !== t3) { t4 = ; - $[4] = t3; - $[5] = data; + $[4] = data; + $[5] = t3; $[6] = t4; } else { t4 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md index 77ded20d939bd..2674d78c997e7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md @@ -48,19 +48,19 @@ function Component(props) { const t1 = props?.items; let t2; - if ($[3] !== t1 || $[4] !== props.cond) { + if ($[3] !== props.cond || $[4] !== t1) { t2 = [t1, props.cond]; - $[3] = t1; - $[4] = props.cond; + $[3] = props.cond; + $[4] = t1; $[5] = t2; } else { t2 = $[5]; } let t3; - if ($[6] !== t2 || $[7] !== data) { + if ($[6] !== data || $[7] !== t2) { t3 = ; - $[6] = t2; - $[7] = data; + $[6] = data; + $[7] = t2; $[8] = t3; } else { t3 = $[8]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md index 10c23085d8e6b..1d4a50d2858ea 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md @@ -48,19 +48,19 @@ function Component(props) { const t1 = props?.items; let t2; - if ($[3] !== t1 || $[4] !== props.cond) { + if ($[3] !== props.cond || $[4] !== t1) { t2 = [t1, props.cond]; - $[3] = t1; - $[4] = props.cond; + $[3] = props.cond; + $[4] = t1; $[5] = t2; } else { t2 = $[5]; } let t3; - if ($[6] !== t2 || $[7] !== data) { + if ($[6] !== data || $[7] !== t2) { t3 = ; - $[6] = t2; - $[7] = data; + $[6] = data; + $[7] = t2; $[8] = t3; } else { t3 = $[8]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md index 398161f0c6a24..42b3b21a20903 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md @@ -31,8 +31,8 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(4); - let y; let t0; + let y; if ($[0] !== props) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -57,11 +57,11 @@ function Component(props) { } } $[0] = props; - $[1] = y; - $[2] = t0; + $[1] = t0; + $[2] = y; } else { - y = $[1]; - t0 = $[2]; + t0 = $[1]; + y = $[2]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-in-other-reactive-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-in-other-reactive-block.expect.md index 9ca63e23c4d72..3da133e9295bc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-in-other-reactive-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-in-other-reactive-block.expect.md @@ -40,7 +40,7 @@ function useFoo(minWidth, otherProp) { const $ = _c(7); const [width] = useState(1); let t0; - if ($[0] !== width || $[1] !== minWidth || $[2] !== otherProp) { + if ($[0] !== minWidth || $[1] !== otherProp || $[2] !== width) { const x = []; let t1; if ($[4] !== minWidth || $[5] !== width) { @@ -55,9 +55,9 @@ function useFoo(minWidth, otherProp) { arrayPush(x, otherProp); t0 = [style, x]; - $[0] = width; - $[1] = minWidth; - $[2] = otherProp; + $[0] = minWidth; + $[1] = otherProp; + $[2] = width; $[3] = t0; } else { t0 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-deplist-controlflow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-deplist-controlflow.expect.md index 947e3bd2eb8ff..ee4e4634cbc21 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-deplist-controlflow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-reordering-deplist-controlflow.expect.md @@ -42,9 +42,9 @@ import { Stringify } from "shared-runtime"; function Foo(t0) { const $ = _c(8); const { arr1, arr2, foo } = t0; - let t1; let getVal1; - if ($[0] !== arr1 || $[1] !== foo || $[2] !== arr2) { + let t1; + if ($[0] !== arr1 || $[1] !== arr2 || $[2] !== foo) { const x = [arr1]; let y; @@ -55,13 +55,13 @@ function Foo(t0) { t1 = () => [y]; foo ? (y = x.concat(arr2)) : y; $[0] = arr1; - $[1] = foo; - $[2] = arr2; - $[3] = t1; - $[4] = getVal1; + $[1] = arr2; + $[2] = foo; + $[3] = getVal1; + $[4] = t1; } else { - t1 = $[3]; - getVal1 = $[4]; + getVal1 = $[3]; + t1 = $[4]; } const getVal2 = t1; let t2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-alloc.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-alloc.expect.md index 3a7016f803d4e..f7353ddd5e97c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-alloc.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-alloc.expect.md @@ -44,10 +44,10 @@ function Component(t0) { t3 = $[1]; } let t4; - if ($[2] !== t3 || $[3] !== propA) { + if ($[2] !== propA || $[3] !== t3) { t4 = { value: t3, other: propA }; - $[2] = t3; - $[3] = propA; + $[2] = propA; + $[3] = t3; $[4] = t4; } else { t4 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-noAlloc.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-noAlloc.expect.md index f0ce9b9114fc4..c6ad9bcdac356 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-noAlloc.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-conditional-access-noAlloc.expect.md @@ -34,10 +34,10 @@ function Component(t0) { const t2 = propB?.x.y; let t3; - if ($[0] !== t2 || $[1] !== propA) { + if ($[0] !== propA || $[1] !== t2) { t3 = { value: t2, other: propA }; - $[0] = t2; - $[1] = propA; + $[0] = propA; + $[1] = t2; $[2] = t3; } else { t3 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-in-other-reactive-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-in-other-reactive-block.expect.md index 9d7feacd6d7f1..7a27bb8521ed5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-in-other-reactive-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-in-other-reactive-block.expect.md @@ -40,7 +40,7 @@ function useFoo(minWidth, otherProp) { const $ = _c(6); const [width] = useState(1); let t0; - if ($[0] !== width || $[1] !== minWidth || $[2] !== otherProp) { + if ($[0] !== minWidth || $[1] !== otherProp || $[2] !== width) { const x = []; let t1; @@ -58,9 +58,9 @@ function useFoo(minWidth, otherProp) { arrayPush(x, otherProp); t0 = [style, x]; - $[0] = width; - $[1] = minWidth; - $[2] = otherProp; + $[0] = minWidth; + $[1] = otherProp; + $[2] = width; $[3] = t0; } else { t0 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-controlflow.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-controlflow.expect.md index e9d2bffb30513..5fc0ec510b3d1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-controlflow.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useMemo-reordering-depslist-controlflow.expect.md @@ -44,7 +44,7 @@ function Foo(t0) { const { arr1, arr2, foo } = t0; let t1; let val1; - if ($[0] !== arr1 || $[1] !== foo || $[2] !== arr2) { + if ($[0] !== arr1 || $[1] !== arr2 || $[2] !== foo) { const x = [arr1]; let y; @@ -63,8 +63,8 @@ function Foo(t0) { foo ? (y = x.concat(arr2)) : y; t1 = (() => [y])(); $[0] = arr1; - $[1] = foo; - $[2] = arr2; + $[1] = arr2; + $[2] = foo; $[3] = t1; $[4] = val1; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-as-dep-nested-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-as-dep-nested-scope.expect.md index e1d4bb5a8ae53..580a97ac19e32 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-as-dep-nested-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-as-dep-nested-scope.expect.md @@ -49,7 +49,7 @@ import { identity, mutate, setProperty } from "shared-runtime"; function PrimitiveAsDepNested(props) { const $ = _c(5); let t0; - if ($[0] !== props.b || $[1] !== props.a) { + if ($[0] !== props.a || $[1] !== props.b) { const x = {}; mutate(x); const t1 = props.b + 1; @@ -64,8 +64,8 @@ function PrimitiveAsDepNested(props) { const y = t2; setProperty(x, props.a); t0 = [x, y]; - $[0] = props.b; - $[1] = props.a; + $[0] = props.a; + $[1] = props.b; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-reassigned-loop-force-scopes-enabled.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-reassigned-loop-force-scopes-enabled.expect.md index 594e68f24feca..de39fc9706a69 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-reassigned-loop-force-scopes-enabled.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/primitive-reassigned-loop-force-scopes-enabled.expect.md @@ -32,15 +32,15 @@ function Component(t0) { const $ = _c(5); const { base, start, increment, test } = t0; let value; - if ($[0] !== base || $[1] !== start || $[2] !== test || $[3] !== increment) { + if ($[0] !== base || $[1] !== increment || $[2] !== start || $[3] !== test) { value = base; for (let i = start; i < test; i = i + increment, i) { value = value + i; } $[0] = base; - $[1] = start; - $[2] = test; - $[3] = increment; + $[1] = increment; + $[2] = start; + $[3] = test; $[4] = value; } else { value = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md index 476e1c017c655..c235681d38c38 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-nested-early-return-within-reactive-scope.expect.md @@ -34,7 +34,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(7); let t0; - if ($[0] !== props.cond || $[1] !== props.a || $[2] !== props.b) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -69,9 +69,9 @@ function Component(props) { break bb0; } } - $[0] = props.cond; - $[1] = props.a; - $[2] = props.b; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; $[3] = t0; } else { t0 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md index bf54b52b59289..0e93d32061fc8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/early-return-within-reactive-scope.expect.md @@ -48,7 +48,7 @@ import { makeArray } from "shared-runtime"; function Component(props) { const $ = _c(6); let t0; - if ($[0] !== props.cond || $[1] !== props.a || $[2] !== props.b) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -69,9 +69,9 @@ function Component(props) { break bb0; } } - $[0] = props.cond; - $[1] = props.a; - $[2] = props.b; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; $[3] = t0; } else { t0 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md index 744824d0bd2c3..2a3da8b195af7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/iife-return-modified-later-phi.expect.md @@ -29,7 +29,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(3); let items; - if ($[0] !== props.cond || $[1] !== props.a) { + if ($[0] !== props.a || $[1] !== props.cond) { let t0; if (props.cond) { t0 = []; @@ -39,8 +39,8 @@ function Component(props) { items = t0; items?.push(props.a); - $[0] = props.cond; - $[1] = props.a; + $[0] = props.a; + $[1] = props.cond; $[2] = items; } else { items = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md index d0486cd8c29fd..28612f2d738dd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-as-memo-dep.expect.md @@ -63,10 +63,10 @@ function Component(t0) { t4 = $[3]; } let t5; - if ($[4] !== t4 || $[5] !== data) { + if ($[4] !== data || $[5] !== t4) { t5 = ; - $[4] = t4; - $[5] = data; + $[4] = data; + $[5] = t4; $[6] = t5; } else { t5 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md index b4a55fcb61eee..2861ab71c6e97 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single-with-unconditional.expect.md @@ -45,10 +45,10 @@ function Component(props) { t1 = $[3]; } let t2; - if ($[4] !== t1 || $[5] !== data) { + if ($[4] !== data || $[5] !== t1) { t2 = ; - $[4] = t1; - $[5] = data; + $[4] = data; + $[5] = t1; $[6] = t2; } else { t2 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md index f15b9b8e9b816..b5db44aa2b6c0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/optional-member-expression-single.expect.md @@ -60,10 +60,10 @@ function Component(t0) { t3 = $[3]; } let t4; - if ($[4] !== t3 || $[5] !== data) { + if ($[4] !== data || $[5] !== t3) { t4 = ; - $[4] = t3; - $[5] = data; + $[4] = data; + $[5] = t3; $[6] = t4; } else { t4 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md index 324eb714fc89b..1972e92237c04 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/partial-early-return-within-reactive-scope.expect.md @@ -32,9 +32,9 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(6); - let y; let t0; - if ($[0] !== props.cond || $[1] !== props.a || $[2] !== props.b) { + let y; + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -57,14 +57,14 @@ function Component(props) { } } } - $[0] = props.cond; - $[1] = props.a; - $[2] = props.b; - $[3] = y; - $[4] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; + $[3] = t0; + $[4] = y; } else { - y = $[3]; - t0 = $[4]; + t0 = $[3]; + y = $[4]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md index 1bfaeb1c84a57..6c7a91ba33b07 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/phi-type-inference-property-store.expect.md @@ -42,7 +42,7 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props.cond || $[2] !== props.a) { + if ($[1] !== props.a || $[2] !== props.cond) { let y; if (props.cond) { y = {}; @@ -53,8 +53,8 @@ function Component(props) { y.x = x; t1 = [x, y]; - $[1] = props.cond; - $[2] = props.a; + $[1] = props.a; + $[2] = props.cond; $[3] = t1; } else { t1 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md index c0f8aa97cd47e..673dd0d5fdf5c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-local-var.expect.md @@ -58,7 +58,7 @@ function useFoo(t0) { local = $[1]; } let t1; - if ($[2] !== shouldReadA || $[3] !== local) { + if ($[2] !== local || $[3] !== shouldReadA) { t1 = ( { @@ -70,8 +70,8 @@ function useFoo(t0) { shouldInvokeFns={true} /> ); - $[2] = shouldReadA; - $[3] = local; + $[2] = local; + $[3] = shouldReadA; $[4] = t1; } else { t1 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md index e37b8365a2faf..abf4c98f23278 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-cond-access-not-hoisted.expect.md @@ -41,7 +41,7 @@ function Foo(t0) { const $ = _c(3); const { a, shouldReadA } = t0; let t1; - if ($[0] !== shouldReadA || $[1] !== a) { + if ($[0] !== a || $[1] !== shouldReadA) { t1 = ( { @@ -53,8 +53,8 @@ function Foo(t0) { shouldInvokeFns={true} /> ); - $[0] = shouldReadA; - $[1] = a; + $[0] = a; + $[1] = shouldReadA; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md index 89b4d281f86dc..d82956e4a0dbc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-access-hoists-other-dep.expect.md @@ -51,13 +51,13 @@ function Foo(t0) { const fn = t1; useIdentity(null); let x; - if ($[2] !== cond || $[3] !== a.b.c) { + if ($[2] !== a.b.c || $[3] !== cond) { x = makeArray(); if (cond) { x.push(identity(a.b.c)); } - $[2] = cond; - $[3] = a.b.c; + $[2] = a.b.c; + $[3] = cond; $[4] = x; } else { x = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md index 591e04de7ba15..c81e59eceaf94 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-function-uncond-optional-hoists-other-dep.expect.md @@ -50,22 +50,22 @@ function Foo(t0) { const fn = t1; useIdentity(null); let arr; - if ($[2] !== cond || $[3] !== a.b?.c.e) { + if ($[2] !== a.b?.c.e || $[3] !== cond) { arr = makeArray(); if (cond) { arr.push(identity(a.b?.c.e)); } - $[2] = cond; - $[3] = a.b?.c.e; + $[2] = a.b?.c.e; + $[3] = cond; $[4] = arr; } else { arr = $[4]; } let t2; - if ($[5] !== fn || $[6] !== arr) { + if ($[5] !== arr || $[6] !== fn) { t2 = ; - $[5] = fn; - $[6] = arr; + $[5] = arr; + $[6] = fn; $[7] = t2; } else { t2 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md index 2c7bf6bbe599e..96d37cee8aa3d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/infer-objectmethod-cond-access.expect.md @@ -41,7 +41,7 @@ function Foo(t0) { const $ = _c(3); const { a, shouldReadA } = t0; let t1; - if ($[0] !== shouldReadA || $[1] !== a) { + if ($[0] !== a || $[1] !== shouldReadA) { t1 = ( ); - $[0] = shouldReadA; - $[1] = a; + $[0] = a; + $[1] = shouldReadA; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md index df9dec4fb6827..277c203525923 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md @@ -24,7 +24,7 @@ import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(5); let x; - if ($[0] !== props.items?.length || $[1] !== props.items?.edges) { + if ($[0] !== props.items?.edges || $[1] !== props.items?.length) { x = []; x.push(props.items?.length); let t0; @@ -36,8 +36,8 @@ function Component(props) { t0 = $[4]; } x.push(t0); - $[0] = props.items?.length; - $[1] = props.items?.edges; + $[0] = props.items?.edges; + $[1] = props.items?.length; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/promote-uncond.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/promote-uncond.expect.md index 902a1578c8870..30cea1e2c8ebb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/promote-uncond.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/reduce-reactive-deps/promote-uncond.expect.md @@ -38,15 +38,15 @@ import { identity } from "shared-runtime"; function usePromoteUnconditionalAccessToDependency(props, other) { const $ = _c(4); let x; - if ($[0] !== props.a.a.a || $[1] !== props.a.b || $[2] !== other) { + if ($[0] !== other || $[1] !== props.a.a.a || $[2] !== props.a.b) { x = {}; x.a = props.a.a.a; if (identity(other)) { x.c = props.a.b.c; } - $[0] = props.a.a.a; - $[1] = props.a.b; - $[2] = other; + $[0] = other; + $[1] = props.a.a.a; + $[2] = props.a.b; $[3] = x; } else { x = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-ternary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-ternary.expect.md index c5cf366fb6101..923830fb4b3bb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-ternary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/ssa-renaming-unconditional-ternary.expect.md @@ -39,11 +39,11 @@ function useFoo(props) { } else { x = $[1]; } - if ($[2] !== props.cond || $[3] !== props.foo || $[4] !== props.bar) { + if ($[2] !== props.bar || $[3] !== props.cond || $[4] !== props.foo) { props.cond ? ((x = []), x.push(props.foo)) : ((x = []), x.push(props.bar)); - $[2] = props.cond; - $[3] = props.foo; - $[4] = props.bar; + $[2] = props.bar; + $[3] = props.cond; + $[4] = props.foo; $[5] = x; } else { x = $[5]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md index 37846215b1d9e..fee31c9fafb87 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch-non-final-default.expect.md @@ -35,8 +35,8 @@ function Component(props) { import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(8); - let y; let t0; + let y; if ($[0] !== props.p0 || $[1] !== props.p2) { const x = []; bb0: switch (props.p0) { @@ -65,19 +65,19 @@ function Component(props) { t0 = ; $[0] = props.p0; $[1] = props.p2; - $[2] = y; - $[3] = t0; + $[2] = t0; + $[3] = y; } else { - y = $[2]; - t0 = $[3]; + t0 = $[2]; + y = $[3]; } const child = t0; y.push(props.p4); let t1; - if ($[5] !== y || $[6] !== child) { + if ($[5] !== child || $[6] !== y) { t1 = {child}; - $[5] = y; - $[6] = child; + $[5] = child; + $[6] = y; $[7] = t1; } else { t1 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md index 1be4143849266..62906680155df 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/switch.expect.md @@ -30,8 +30,8 @@ function Component(props) { import { c as _c } from "react/compiler-runtime"; // @enablePropagateDepsInHIR function Component(props) { const $ = _c(8); - let y; let t0; + let y; if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) { const x = []; switch (props.p0) { @@ -48,19 +48,19 @@ function Component(props) { $[0] = props.p0; $[1] = props.p2; $[2] = props.p3; - $[3] = y; - $[4] = t0; + $[3] = t0; + $[4] = y; } else { - y = $[3]; - t0 = $[4]; + t0 = $[3]; + y = $[4]; } const child = t0; y.push(props.p4); let t1; - if ($[5] !== y || $[6] !== child) { + if ($[5] !== child || $[6] !== y) { t1 = {child}; - $[5] = y; - $[6] = child; + $[5] = child; + $[6] = y; $[7] = t1; } else { t1 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md index f69994b0a8531..5cd81990e86bd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch-escaping.expect.md @@ -34,7 +34,7 @@ const { throwInput } = require("shared-runtime"); function Component(props) { const $ = _c(3); let x; - if ($[0] !== props.y || $[1] !== props.e) { + if ($[0] !== props.e || $[1] !== props.y) { try { const y = []; y.push(props.y); @@ -44,8 +44,8 @@ function Component(props) { e.push(props.e); x = e; } - $[0] = props.y; - $[1] = props.e; + $[0] = props.e; + $[1] = props.y; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md index bc47228371f87..dc41af6275078 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/try-catch-try-value-modified-in-catch.expect.md @@ -33,7 +33,7 @@ const { throwInput } = require("shared-runtime"); function Component(props) { const $ = _c(3); let t0; - if ($[0] !== props.y || $[1] !== props.e) { + if ($[0] !== props.e || $[1] !== props.y) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { try { @@ -47,8 +47,8 @@ function Component(props) { break bb0; } } - $[0] = props.y; - $[1] = props.e; + $[0] = props.e; + $[1] = props.y; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md index d654221dc837e..a75b592b83232 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/propagate-scope-deps-hir-fork/useMemo-multiple-if-else.expect.md @@ -39,10 +39,10 @@ function Component(props) { bb0: { let y; if ( - $[0] !== props.cond || - $[1] !== props.a || - $[2] !== props.cond2 || - $[3] !== props.b + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.cond || + $[3] !== props.cond2 ) { y = []; if (props.cond) { @@ -54,10 +54,10 @@ function Component(props) { } y.push(props.b); - $[0] = props.cond; - $[1] = props.a; - $[2] = props.cond2; - $[3] = props.b; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; + $[3] = props.cond2; $[4] = y; $[5] = t0; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md index 7480362a43798..c6331bd4a0873 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-interleaved-reactivity.expect.md @@ -54,10 +54,10 @@ function Component(props) { } const c = t0; let t1; - if ($[3] !== c || $[4] !== a) { + if ($[3] !== a || $[4] !== c) { t1 = [c, a]; - $[3] = c; - $[4] = a; + $[3] = a; + $[4] = c; $[5] = t1; } else { t1 = $[5]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-computed-load.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-computed-load.expect.md index 29e3e2757ff68..5ac29886cf835 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-computed-load.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-computed-load.expect.md @@ -20,11 +20,11 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(8); let items; - if ($[0] !== props.key || $[1] !== props.a) { + if ($[0] !== props.a || $[1] !== props.key) { items = bar(); mutate(items[props.key], props.a); - $[0] = props.key; - $[1] = props.a; + $[0] = props.a; + $[1] = props.key; $[2] = items; } else { items = $[2]; @@ -41,10 +41,10 @@ function Component(props) { } const count = t1; let t2; - if ($[5] !== items || $[6] !== count) { + if ($[5] !== count || $[6] !== items) { t2 = { items, count }; - $[5] = items; - $[6] = count; + $[5] = count; + $[6] = items; $[7] = t2; } else { t2 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-property-load.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-property-load.expect.md index 3408f707d67a9..bb76df4de029b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-property-load.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactivity-analysis-reactive-via-mutation-of-property-load.expect.md @@ -40,10 +40,10 @@ function Component(props) { } const count = t1; let t2; - if ($[4] !== items || $[5] !== count) { + if ($[4] !== count || $[5] !== items) { t2 = { items, count }; - $[4] = items; - $[5] = count; + $[4] = count; + $[5] = items; $[6] = t2; } else { t2 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-separate-scopes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-separate-scopes.expect.md index e682a01086546..422f4cf54754a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-separate-scopes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassignment-separate-scopes.expect.md @@ -42,8 +42,8 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function foo(a, b, c) { const $ = _c(10); - let x; let t0; + let x; if ($[0] !== a) { x = []; if (a) { @@ -52,11 +52,11 @@ function foo(a, b, c) { t0 =
{x}
; $[0] = a; - $[1] = x; - $[2] = t0; + $[1] = t0; + $[2] = x; } else { - x = $[1]; - t0 = $[2]; + t0 = $[1]; + x = $[2]; } const y = t0; bb0: switch (b) { @@ -83,15 +83,15 @@ function foo(a, b, c) { } } let t1; - if ($[7] !== y || $[8] !== x) { + if ($[7] !== x || $[8] !== y) { t1 = (
{y} {x}
); - $[7] = y; - $[8] = x; + $[7] = x; + $[8] = y; $[9] = t1; } else { t1 = $[9]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-break-in-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-break-in-scope.expect.md index 3ad544344d6d9..f3ddf57ec0099 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-break-in-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-break-in-scope.expect.md @@ -34,7 +34,7 @@ function useFoo(t0) { const $ = _c(3); const { obj, objIsNull } = t0; let x; - if ($[0] !== objIsNull || $[1] !== obj) { + if ($[0] !== obj || $[1] !== objIsNull) { x = []; bb0: { if (objIsNull) { @@ -45,8 +45,8 @@ function useFoo(t0) { x.push(obj.b); } - $[0] = objIsNull; - $[1] = obj; + $[0] = obj; + $[1] = objIsNull; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-return-in-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-return-in-scope.expect.md index 449aa6d3d86f5..5700634449eae 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-return-in-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-cond-deps-return-in-scope.expect.md @@ -31,9 +31,9 @@ import { c as _c } from "react/compiler-runtime"; function useFoo(t0) { const $ = _c(4); const { obj, objIsNull } = t0; - let x; let t1; - if ($[0] !== objIsNull || $[1] !== obj) { + let x; + if ($[0] !== obj || $[1] !== objIsNull) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { x = []; @@ -46,13 +46,13 @@ function useFoo(t0) { x.push(obj.b); } - $[0] = objIsNull; - $[1] = obj; - $[2] = x; - $[3] = t1; + $[0] = obj; + $[1] = objIsNull; + $[2] = t1; + $[3] = x; } else { - x = $[2]; - t1 = $[3]; + t1 = $[2]; + x = $[3]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md index 4d45d3f3c6da6..18e9faf63b5dc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md @@ -38,7 +38,7 @@ function Foo(t0) { const $ = _c(3); const { a, shouldReadA } = t0; let t1; - if ($[0] !== shouldReadA || $[1] !== a.b.c) { + if ($[0] !== a.b.c || $[1] !== shouldReadA) { t1 = ( { @@ -50,8 +50,8 @@ function Foo(t0) { shouldInvokeFns={true} /> ); - $[0] = shouldReadA; - $[1] = a.b.c; + $[0] = a.b.c; + $[1] = shouldReadA; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/hoist-deps-diff-ssa-instance.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/hoist-deps-diff-ssa-instance.expect.md index 701702f9dd7ff..2dd9362404931 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/hoist-deps-diff-ssa-instance.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/hoist-deps-diff-ssa-instance.expect.md @@ -80,10 +80,10 @@ function useFoo(t0) { x = $[6]; } let t1; - if ($[7] !== y || $[8] !== x.a.b) { + if ($[7] !== x.a.b || $[8] !== y) { t1 = [y, x.a.b]; - $[7] = y; - $[8] = x.a.b; + $[7] = x.a.b; + $[8] = y; $[9] = t1; } else { t1 = $[9]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/break-in-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/break-in-scope.expect.md index b4c25d5f45041..e024bc893a034 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/break-in-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/break-in-scope.expect.md @@ -36,7 +36,7 @@ function useFoo(t0) { const $ = _c(3); const { obj, objIsNull } = t0; let x; - if ($[0] !== objIsNull || $[1] !== obj) { + if ($[0] !== obj || $[1] !== objIsNull) { x = []; bb0: { if (objIsNull) { @@ -45,8 +45,8 @@ function useFoo(t0) { x.push(obj.a); } - $[0] = objIsNull; - $[1] = obj; + $[0] = obj; + $[1] = objIsNull; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/loop-break-in-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/loop-break-in-scope.expect.md index 359ba0dcde90f..055d1ce12e4f0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/loop-break-in-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/loop-break-in-scope.expect.md @@ -36,7 +36,7 @@ function useFoo(t0) { const $ = _c(3); const { obj, objIsNull } = t0; let x; - if ($[0] !== objIsNull || $[1] !== obj) { + if ($[0] !== obj || $[1] !== objIsNull) { x = []; for (let i = 0; i < 5; i++) { if (objIsNull) { @@ -45,8 +45,8 @@ function useFoo(t0) { x.push(obj.a); } - $[0] = objIsNull; - $[1] = obj; + $[0] = obj; + $[1] = objIsNull; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps.expect.md index bb4758768738d..1c2162352b3b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps.expect.md @@ -42,8 +42,8 @@ import { identity } from "shared-runtime"; function useFoo(t0) { const $ = _c(9); const { input, cond, hasAB } = t0; - let x; let t1; + let x; if ($[0] !== cond || $[1] !== hasAB || $[2] !== input) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -77,11 +77,11 @@ function useFoo(t0) { $[0] = cond; $[1] = hasAB; $[2] = input; - $[3] = x; - $[4] = t1; + $[3] = t1; + $[4] = x; } else { - x = $[3]; - t1 = $[4]; + t1 = $[3]; + x = $[4]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps1.expect.md index 59225b51551bc..ca8228e2db0b0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/reduce-if-nonexhaustive-poisoned-deps1.expect.md @@ -43,8 +43,8 @@ import { identity } from "shared-runtime"; function useFoo(t0) { const $ = _c(11); const { input, cond, hasAB } = t0; - let x; let t1; + let x; if ($[0] !== cond || $[1] !== hasAB || $[2] !== input) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -88,11 +88,11 @@ function useFoo(t0) { $[0] = cond; $[1] = hasAB; $[2] = input; - $[3] = x; - $[4] = t1; + $[3] = t1; + $[4] = x; } else { - x = $[3]; - t1 = $[4]; + t1 = $[3]; + x = $[4]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-in-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-in-scope.expect.md index 7a7f9a4b6ec29..ce12fb17b068f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-in-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-in-scope.expect.md @@ -33,9 +33,9 @@ import { c as _c } from "react/compiler-runtime"; function useFoo(t0) { const $ = _c(4); const { obj, objIsNull } = t0; - let x; let t1; - if ($[0] !== objIsNull || $[1] !== obj) { + let x; + if ($[0] !== obj || $[1] !== objIsNull) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { x = []; @@ -46,13 +46,13 @@ function useFoo(t0) { x.push(obj.b); } - $[0] = objIsNull; - $[1] = obj; - $[2] = x; - $[3] = t1; + $[0] = obj; + $[1] = objIsNull; + $[2] = t1; + $[3] = x; } else { - x = $[2]; - t1 = $[3]; + t1 = $[2]; + x = $[3]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-poisons-outer-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-poisons-outer-scope.expect.md index 2b925c24797e1..058bf85b69f3f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-poisons-outer-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-poisoned/return-poisons-outer-scope.expect.md @@ -39,8 +39,8 @@ import { identity } from "shared-runtime"; function useFoo(t0) { const $ = _c(6); const { input, cond } = t0; - let x; let t1; + let x; if ($[0] !== cond || $[1] !== input) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -61,11 +61,11 @@ function useFoo(t0) { } $[0] = cond; $[1] = input; - $[2] = x; - $[3] = t1; + $[2] = t1; + $[3] = x; } else { - x = $[2]; - t1 = $[3]; + t1 = $[2]; + x = $[3]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/jump-target-within-scope-loop-break.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/jump-target-within-scope-loop-break.expect.md index 291998c8ad718..2715a0c92dac3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/jump-target-within-scope-loop-break.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/jump-target-within-scope-loop-break.expect.md @@ -40,7 +40,7 @@ function useFoo(t0) { const $ = _c(3); const { input, max } = t0; let x; - if ($[0] !== max || $[1] !== input.a.b) { + if ($[0] !== input.a.b || $[1] !== max) { x = []; let i = 0; while (true) { @@ -52,8 +52,8 @@ function useFoo(t0) { x.push(i); x.push(input.a.b); - $[0] = max; - $[1] = input.a.b; + $[0] = input.a.b; + $[1] = max; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps.expect.md index 84b8fa1d43d54..845ea4b5ac2d4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps.expect.md @@ -33,8 +33,8 @@ import { identity } from "shared-runtime"; function useFoo(t0) { const $ = _c(9); const { input, hasAB, returnNull } = t0; - let x; let t1; + let x; if ($[0] !== hasAB || $[1] !== input.a || $[2] !== returnNull) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -68,11 +68,11 @@ function useFoo(t0) { $[0] = hasAB; $[1] = input.a; $[2] = returnNull; - $[3] = x; - $[4] = t1; + $[3] = t1; + $[4] = x; } else { - x = $[3]; - t1 = $[4]; + t1 = $[3]; + x = $[4]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps1.expect.md index a55922f610486..d3e463495bb34 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/jump-unpoisoned/reduce-if-exhaustive-nonpoisoned-deps1.expect.md @@ -43,8 +43,8 @@ import { identity } from "shared-runtime"; function useFoo(t0) { const $ = _c(11); const { input, cond2, cond1 } = t0; - let x; let t1; + let x; if ($[0] !== cond1 || $[1] !== cond2 || $[2] !== input.a.b) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -88,11 +88,11 @@ function useFoo(t0) { $[0] = cond1; $[1] = cond2; $[2] = input.a.b; - $[3] = x; - $[4] = t1; + $[3] = t1; + $[4] = x; } else { - x = $[3]; - t1 = $[4]; + t1 = $[3]; + x = $[4]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md index 8d69c008c573b..7818ca4e0da54 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/memberexpr-join-optional-chain2.expect.md @@ -23,7 +23,7 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(5); let x; - if ($[0] !== props.items?.length || $[1] !== props.items?.edges) { + if ($[0] !== props.items?.edges || $[1] !== props.items?.length) { x = []; x.push(props.items?.length); let t0; @@ -35,8 +35,8 @@ function Component(props) { t0 = $[4]; } x.push(t0); - $[0] = props.items?.length; - $[1] = props.items?.edges; + $[0] = props.items?.edges; + $[1] = props.items?.length; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md index 09806d8b4b15d..d3a61a1019c4b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md @@ -36,14 +36,14 @@ import { identity } from "shared-runtime"; function usePromoteUnconditionalAccessToDependency(props, other) { const $ = _c(3); let x; - if ($[0] !== props.a || $[1] !== other) { + if ($[0] !== other || $[1] !== props.a) { x = {}; x.a = props.a.a.a; if (identity(other)) { x.c = props.a.b.c; } - $[0] = props.a; - $[1] = other; + $[0] = other; + $[1] = props.a; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/reduce-if-exhaustive-poisoned-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/reduce-if-exhaustive-poisoned-deps.expect.md index 01ab4f6b0a537..41a7a25d63a31 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/reduce-if-exhaustive-poisoned-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/reduce-if-exhaustive-poisoned-deps.expect.md @@ -34,9 +34,9 @@ import { identity } from "shared-runtime"; function useFoo(t0) { const $ = _c(11); const { input, inputHasAB, inputHasABC } = t0; - let x; let t1; - if ($[0] !== inputHasABC || $[1] !== input.a || $[2] !== inputHasAB) { + let x; + if ($[0] !== input.a || $[1] !== inputHasAB || $[2] !== inputHasABC) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { x = []; @@ -75,14 +75,14 @@ function useFoo(t0) { x.push(t2); } } - $[0] = inputHasABC; - $[1] = input.a; - $[2] = inputHasAB; - $[3] = x; - $[4] = t1; + $[0] = input.a; + $[1] = inputHasAB; + $[2] = inputHasABC; + $[3] = t1; + $[4] = x; } else { - x = $[3]; - t1 = $[4]; + t1 = $[3]; + x = $[4]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/subpath-order1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/subpath-order1.expect.md index a62223d72d993..03e3e96397958 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/subpath-order1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/subpath-order1.expect.md @@ -40,14 +40,14 @@ import { identity } from "shared-runtime"; function useConditionalSubpath1(props, cond) { const $ = _c(3); let x; - if ($[0] !== props.a || $[1] !== cond) { + if ($[0] !== cond || $[1] !== props.a) { x = {}; x.b = props.a.b; if (identity(cond)) { x.a = props.a; } - $[0] = props.a; - $[1] = cond; + $[0] = cond; + $[1] = props.a; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/superpath-order1.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/superpath-order1.expect.md index 02117feee2c2c..5b246175f9644 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/superpath-order1.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/superpath-order1.expect.md @@ -48,14 +48,14 @@ function useConditionalSuperpath1(t0) { const $ = _c(3); const { props, cond } = t0; let x; - if ($[0] !== props.a || $[1] !== cond) { + if ($[0] !== cond || $[1] !== props.a) { x = {}; x.a = props.a; if (identity(cond)) { x.b = props.a.b; } - $[0] = props.a; - $[1] = cond; + $[0] = cond; + $[1] = props.a; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-access-in-mutable-range.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-access-in-mutable-range.expect.md index 34979e9de9485..c91cf94445ca9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-access-in-mutable-range.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-access-in-mutable-range.expect.md @@ -49,15 +49,15 @@ function Component(t0) { const $ = _c(8); const { cond, other } = t0; let x; - if ($[0] !== other || $[1] !== cond) { + if ($[0] !== cond || $[1] !== other) { x = makeObject_Primitives(); setProperty(x, { b: 3, other }, "a"); identity(x.a.b); if (!cond) { x.a = null; } - $[0] = other; - $[1] = cond; + $[0] = cond; + $[1] = other; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-nonoverlap-descendant.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-nonoverlap-descendant.expect.md index 0a1a423361037..ff15f1a336023 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-nonoverlap-descendant.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/uncond-nonoverlap-descendant.expect.md @@ -27,13 +27,13 @@ import { c as _c } from "react/compiler-runtime"; // Test that we can track non- function TestNonOverlappingDescendantTracked(props) { const $ = _c(4); let x; - if ($[0] !== props.a.x.y || $[1] !== props.a.c.x.y.z || $[2] !== props.b) { + if ($[0] !== props.a.c.x.y.z || $[1] !== props.a.x.y || $[2] !== props.b) { x = {}; x.a = props.a.x.y; x.b = props.b; x.c = props.a.c.x.y.z; - $[0] = props.a.x.y; - $[1] = props.a.c.x.y.z; + $[0] = props.a.c.x.y.z; + $[1] = props.a.x.y; $[2] = props.b; $[3] = x; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.expect.md index da6912d35e0b4..a2bd99e9a7691 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reordering-across-blocks.expect.md @@ -82,10 +82,10 @@ function Component(t0) { } const b = t3; let t4; - if ($[4] !== b || $[5] !== a) { + if ($[4] !== a || $[5] !== b) { t4 = { b, a }; - $[4] = b; - $[5] = a; + $[4] = a; + $[5] = b; $[6] = t4; } else { t4 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-independently-memoized-property-load-for-method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-independently-memoized-property-load-for-method-call.expect.md index bba0b3f1392ba..0089d20af2ff3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-independently-memoized-property-load-for-method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-independently-memoized-property-load-for-method-call.expect.md @@ -59,7 +59,7 @@ function Component(t0) { const serverTime = useServerTime(); let t1; let timestampLabel; - if ($[0] !== highlightedItem || $[1] !== serverTime || $[2] !== label) { + if ($[0] !== highlightedItem || $[1] !== label || $[2] !== serverTime) { const highlight = new Highlight(highlightedItem); const time = serverTime.get(); @@ -68,8 +68,8 @@ function Component(t0) { t1 = highlight.render(); $[0] = highlightedItem; - $[1] = serverTime; - $[2] = label; + $[1] = label; + $[2] = serverTime; $[3] = t1; $[4] = timestampLabel; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value-via-alias.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value-via-alias.expect.md index 9c21dc84004f7..ecdfa88b98013 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value-via-alias.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value-via-alias.expect.md @@ -66,10 +66,10 @@ function MyApp(t0) { const z = makeObject_Primitives(); const x = useIdentity(2); let t1; - if ($[0] !== x || $[1] !== count) { + if ($[0] !== count || $[1] !== x) { t1 = sum(x, count); - $[0] = x; - $[1] = count; + $[0] = count; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value.expect.md index 1b6e91a6fdd3d..f9d725e0b3558 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-pruned-scope-leaks-value.expect.md @@ -65,10 +65,10 @@ function MyApp(t0) { const z = makeObject_Primitives(); const x = useIdentity(2); let t1; - if ($[0] !== x || $[1] !== count) { + if ($[0] !== count || $[1] !== x) { t1 = sum(x, count); - $[0] = x; - $[1] = count; + $[0] = count; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md index 2dabc256f9ec2..1ad6f6a0477c3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-invalid-reactivity-value-block.expect.md @@ -71,10 +71,10 @@ function Foo() { const shouldCaptureObj = obj != null && CONST_TRUE; const t0 = shouldCaptureObj ? identity(obj) : null; let t1; - if ($[0] !== t0 || $[1] !== obj) { + if ($[0] !== obj || $[1] !== t0) { t1 = [t0, obj]; - $[0] = t0; - $[1] = obj; + $[0] = obj; + $[1] = t0; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md index 4921fd340b1ce..d35cbe266f631 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types-explicit-types.expect.md @@ -77,15 +77,15 @@ function Component() { const map = t3; const index = filtered.findIndex(_temp3); let t5; - if ($[8] !== map || $[9] !== index) { + if ($[8] !== index || $[9] !== map) { t5 = (
{map} {index}
); - $[8] = map; - $[9] = index; + $[8] = index; + $[9] = map; $[10] = t5; } else { t5 = $[10]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md index 80d046ec1807a..eda7a0cbfebc5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-missing-memoization-lack-of-phi-types.expect.md @@ -74,15 +74,15 @@ function Component() { const map = t3; const index = filtered.findIndex(_temp3); let t5; - if ($[8] !== map || $[9] !== index) { + if ($[8] !== index || $[9] !== map) { t5 = (
{map} {index}
); - $[8] = map; - $[9] = index; + $[8] = index; + $[9] = map; $[10] = t5; } else { t5 = $[10]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md index 5eff1aa0fe5e2..b5a78277288d8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-no-value-for-temporary.expect.md @@ -21,13 +21,13 @@ function Component(listItem, thread) { let t0; let t1; let t2; - if ($[0] !== thread.threadType || $[1] !== listItem) { + if ($[0] !== listItem || $[1] !== thread.threadType) { const isFoo = isFooThread(thread.threadType); t1 = useBar; t2 = listItem; t0 = getBadgeText(listItem, isFoo); - $[0] = thread.threadType; - $[1] = listItem; + $[0] = listItem; + $[1] = thread.threadType; $[2] = t0; $[3] = t1; $[4] = t2; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-propagate-type-of-ternary-jsx.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-propagate-type-of-ternary-jsx.expect.md index 1d4a4b5d671ed..32cbbb2b918a2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-propagate-type-of-ternary-jsx.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-propagate-type-of-ternary-jsx.expect.md @@ -28,7 +28,7 @@ function V0(t0) { const { v1, v2 } = t0; const v5 = v1.v6?.v7; let t1; - if ($[0] !== v5 || $[1] !== v1 || $[2] !== v2) { + if ($[0] !== v1 || $[1] !== v2 || $[2] !== v5) { t1 = ( {v5 != null ? ( @@ -40,9 +40,9 @@ function V0(t0) { )} ); - $[0] = v5; - $[1] = v1; - $[2] = v2; + $[0] = v1; + $[1] = v2; + $[2] = v5; $[3] = t1; } else { t1 = $[3]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md index cec64e8cf0d9e..ab409b366d9c2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-slow-validate-preserve-memo.expect.md @@ -36,7 +36,7 @@ function useTest(t0) { const $ = _c(3); const { isNull, data } = t0; let t1; - if ($[0] !== isNull || $[1] !== data) { + if ($[0] !== data || $[1] !== isNull) { t1 = Builder.makeBuilder(isNull, "hello world") ?.push("1", 2) ?.push(3, { a: 4, b: 5, c: data }) @@ -47,8 +47,8 @@ function useTest(t0) { ) ?.push(7, "8") ?.push("8", Builder.makeBuilder(!isNull)?.push(9).vals)?.vals; - $[0] = isNull; - $[1] = data; + $[0] = data; + $[1] = isNull; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unmerged-fbt-call-merge-overlapping-reactive-scopes.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unmerged-fbt-call-merge-overlapping-reactive-scopes.expect.md index 31180b22364f6..fe7857a355efb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unmerged-fbt-call-merge-overlapping-reactive-scopes.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unmerged-fbt-call-merge-overlapping-reactive-scopes.expect.md @@ -38,7 +38,7 @@ import { Stringify } from "shared-runtime"; function Component(props) { const $ = _c(3); let t0; - if ($[0] !== props.value.length || $[1] !== props.cond) { + if ($[0] !== props.cond || $[1] !== props.value.length) { const label = fbt._( { "*": "{number} bars", _1: "1 bar" }, [fbt._plural(props.value.length, "number")], @@ -51,8 +51,8 @@ function Component(props) { label={label.toString()} /> ) : null; - $[0] = props.value.length; - $[1] = props.cond; + $[0] = props.cond; + $[1] = props.value.length; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md index 73674e5ffff43..496d80d52b027 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro-unreachable-code-early-return-in-useMemo.expect.md @@ -77,10 +77,10 @@ function Component(t0) { t2 = $[3]; } let t3; - if ($[4] !== t2 || $[5] !== result) { + if ($[4] !== result || $[5] !== t2) { t3 = ; - $[4] = t2; - $[5] = result; + $[4] = result; + $[5] = t2; $[6] = t3; } else { t3 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md index 2e9daceed798a..1b49552bea135 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/repro.expect.md @@ -26,8 +26,8 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(7); const item = props.item; - let t0; let baseVideos; + let t0; let thumbnails; if ($[0] !== item) { thumbnails = []; @@ -40,12 +40,12 @@ function Component(props) { } }); $[0] = item; - $[1] = t0; - $[2] = baseVideos; + $[1] = baseVideos; + $[2] = t0; $[3] = thumbnails; } else { - t0 = $[1]; - baseVideos = $[2]; + baseVideos = $[1]; + t0 = $[2]; thumbnails = $[3]; } t0 = undefined; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md index 9aa75b2162515..aece9665c920c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-array-pattern.expect.md @@ -21,10 +21,10 @@ function Component(foo, ...t0) { const $ = _c(3); const [bar] = t0; let t1; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t1 = [foo, bar]; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md index ded1eb4006100..3681e9c469955 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-identifier.expect.md @@ -21,10 +21,10 @@ function Component(foo, ...t0) { const $ = _c(3); const bar = t0; let t1; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t1 = [foo, bar]; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md index f0a46be168a06..3e66b200411b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/rest-param-with-object-spread-pattern.expect.md @@ -21,10 +21,10 @@ function Component(foo, ...t0) { const $ = _c(3); const { bar } = t0; let t1; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t1 = [foo, bar]; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md index 7c9c6a50289f2..1201a9a737439 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare-maybe-frozen.expect.md @@ -73,14 +73,14 @@ function foo(props) { } const header = t0; let y; - if ($[5] !== x || $[6] !== props.b || $[7] !== props.c) { + if ($[5] !== props.b || $[6] !== props.c || $[7] !== x) { y = [x]; x = []; y.push(props.b); x.push(props.c); - $[5] = x; - $[6] = props.b; - $[7] = props.c; + $[5] = props.b; + $[6] = props.c; + $[7] = x; $[8] = y; $[9] = x; } else { @@ -103,15 +103,15 @@ function foo(props) { } const content = t1; let t2; - if ($[13] !== header || $[14] !== content) { + if ($[13] !== content || $[14] !== header) { t2 = ( <> {header} {content} ); - $[13] = header; - $[14] = content; + $[13] = content; + $[14] = header; $[15] = t2; } else { t2 = $[15]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare.expect.md index 36b1d4541ae57..143496678edd3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/same-variable-as-dep-and-redeclare.expect.md @@ -53,30 +53,30 @@ import { c as _c } from "react/compiler-runtime"; // note: comments are for the // emitted function foo(props) { const $ = _c(14); - let x; let t0; + let x; if ($[0] !== props.a) { x = []; x.push(props.a); t0 =
{x}
; $[0] = props.a; - $[1] = x; - $[2] = t0; + $[1] = t0; + $[2] = x; } else { - x = $[1]; - t0 = $[2]; + t0 = $[1]; + x = $[2]; } const header = t0; let y; - if ($[3] !== x || $[4] !== props.b || $[5] !== props.c) { + if ($[3] !== props.b || $[4] !== props.c || $[5] !== x) { y = [x]; x = []; y.push(props.b); x.push(props.c); - $[3] = x; - $[4] = props.b; - $[5] = props.c; + $[3] = props.b; + $[4] = props.c; + $[5] = x; $[6] = y; $[7] = x; } else { @@ -99,15 +99,15 @@ function foo(props) { } const content = t1; let t2; - if ($[11] !== header || $[12] !== content) { + if ($[11] !== content || $[12] !== header) { t2 = ( <> {header} {content} ); - $[11] = header; - $[12] = content; + $[11] = content; + $[12] = header; $[13] = t2; } else { t2 = $[13]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-assignment-to-scope-declarations.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-assignment-to-scope-declarations.expect.md index 5f10f44202d02..36a68d07c46c9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-assignment-to-scope-declarations.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-assignment-to-scope-declarations.expect.md @@ -43,9 +43,9 @@ import { identity } from "shared-runtime"; function Component(statusName) { const $ = _c(12); - let text; let t0; let t1; + let text; if ($[0] !== statusName) { const { status, text: t2 } = foo(statusName); text = t2; @@ -54,13 +54,13 @@ function Component(statusName) { t1 = identity(bg); t0 = identity(color); $[0] = statusName; - $[1] = text; - $[2] = t0; - $[3] = t1; + $[1] = t0; + $[2] = t1; + $[3] = text; } else { - text = $[1]; - t0 = $[2]; - t1 = $[3]; + t0 = $[1]; + t1 = $[2]; + text = $[3]; } let t2; if ($[4] !== text) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-both-mixed-local-and-scope-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-both-mixed-local-and-scope-declaration.expect.md index e2cd53bd0d03a..d8e991dc46a08 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-both-mixed-local-and-scope-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/sequential-destructuring-both-mixed-local-and-scope-declaration.expect.md @@ -46,9 +46,9 @@ import { identity } from "shared-runtime"; function Component(statusName) { const $ = _c(12); + let font; let t0; let text; - let font; if ($[0] !== statusName) { const { status, text: t1 } = foo(statusName); text = t1; @@ -58,13 +58,13 @@ function Component(statusName) { t0 = identity(color); $[0] = statusName; - $[1] = t0; - $[2] = text; - $[3] = font; + $[1] = font; + $[2] = t0; + $[3] = text; } else { - t0 = $[1]; - text = $[2]; - font = $[3]; + font = $[1]; + t0 = $[2]; + text = $[3]; } const bg = t0; let t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md index 915218fcfa467..788109636b680 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md @@ -34,8 +34,8 @@ function Component(props) { import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(7); - let y; let t0; + let y; if ($[0] !== props) { const x = []; bb0: switch (props.p0) { @@ -63,19 +63,19 @@ function Component(props) { t0 = ; $[0] = props; - $[1] = y; - $[2] = t0; + $[1] = t0; + $[2] = y; } else { - y = $[1]; - t0 = $[2]; + t0 = $[1]; + y = $[2]; } const child = t0; y.push(props.p4); let t1; - if ($[4] !== y || $[5] !== child) { + if ($[4] !== child || $[5] !== y) { t1 = {child}; - $[4] = y; - $[5] = child; + $[4] = child; + $[5] = y; $[6] = t1; } else { t1 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md index 0c5aea9c7da9c..2628982655deb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md @@ -29,8 +29,8 @@ function Component(props) { import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(6); - let y; let t0; + let y; if ($[0] !== props) { const x = []; switch (props.p0) { @@ -45,19 +45,19 @@ function Component(props) { t0 = ; $[0] = props; - $[1] = y; - $[2] = t0; + $[1] = t0; + $[2] = y; } else { - y = $[1]; - t0 = $[2]; + t0 = $[1]; + y = $[2]; } const child = t0; y.push(props.p4); let t1; - if ($[3] !== y || $[4] !== child) { + if ($[3] !== child || $[4] !== y) { t1 = {child}; - $[3] = y; - $[4] = child; + $[3] = child; + $[4] = y; $[5] = t1; } else { t1 = $[5]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md index f106382d64176..4864c51a1fe25 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md @@ -50,7 +50,7 @@ function Component(t0) { const { arr } = t0; const x = useX(); let t1; - if ($[0] !== x || $[1] !== arr) { + if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { t2 = (i, id) => ( @@ -64,8 +64,8 @@ function Component(t0) { t2 = $[4]; } t1 = arr.map(t2); - $[0] = x; - $[1] = arr; + $[0] = arr; + $[1] = x; $[2] = t1; } else { t1 = $[2]; @@ -85,15 +85,15 @@ function Bar(t0) { const $ = _c(3); const { x, children } = t0; let t1; - if ($[0] !== x || $[1] !== children) { + if ($[0] !== children || $[1] !== x) { t1 = ( <> {x} {children} ); - $[0] = x; - $[1] = children; + $[0] = children; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md index 77fd38aea1eb5..c661094fdd455 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md @@ -55,7 +55,7 @@ function Component(t0) { const { arr } = t0; const x = useX(); let t1; - if ($[0] !== x || $[1] !== arr) { + if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { t2 = (i, id) => ( @@ -70,8 +70,8 @@ function Component(t0) { t2 = $[4]; } t1 = arr.map(t2); - $[0] = x; - $[1] = arr; + $[0] = arr; + $[1] = x; $[2] = t1; } else { t1 = $[2]; @@ -91,15 +91,15 @@ function Bar(t0) { const $ = _c(3); const { x, children } = t0; let t1; - if ($[0] !== x || $[1] !== children) { + if ($[0] !== children || $[1] !== x) { t1 = ( <> {x} {children} ); - $[0] = x; - $[1] = children; + $[0] = children; + $[1] = x; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-array-destructuring.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-array-destructuring.expect.md index d064a48b7197a..7ac6486b47037 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-array-destructuring.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-array-destructuring.expect.md @@ -18,10 +18,10 @@ function App() { const $ = _c(3); const [foo, bar] = useContext(MyContext); let t0; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t0 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-destructure-multiple.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-destructure-multiple.expect.md index f82af06866b76..3eac66304be68 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-destructure-multiple.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-destructure-multiple.expect.md @@ -22,10 +22,10 @@ function App() { const { foo } = context; const { bar } = context; let t0; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t0 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-mixed-array-obj.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-mixed-array-obj.expect.md index 573b6db231c1e..4cca8b19d95cd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-mixed-array-obj.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-mixed-array-obj.expect.md @@ -22,10 +22,10 @@ function App() { const [foo] = context; const { bar } = context; let t0; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t0 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-nested-destructuring.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-nested-destructuring.expect.md index 03ce7f97ba357..f5a3916626913 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-nested-destructuring.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-nested-destructuring.expect.md @@ -22,10 +22,10 @@ function App() { const { joe: t0, bar } = useContext(MyContext); const { foo } = t0; let t1; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t1 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-property-load.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-property-load.expect.md index 55387503cf744..0888d67b2aa94 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-property-load.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.lower-context-access-property-load.expect.md @@ -22,10 +22,10 @@ function App() { const foo = context.foo; const bar = context.bar; let t0; - if ($[0] !== foo || $[1] !== bar) { + if ($[0] !== bar || $[1] !== foo) { t0 = ; - $[0] = foo; - $[1] = bar; + $[0] = bar; + $[1] = foo; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-in-nested-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-in-nested-scope.expect.md index 268fa8d7eba35..2c27360c9fede 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-in-nested-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-in-nested-scope.expect.md @@ -42,9 +42,9 @@ import { mutate, setProperty, throwErrorWithMessageIf } from "shared-runtime"; function useFoo(t0) { const $ = _c(6); const { value, cond } = t0; - let y; let t1; - if ($[0] !== value || $[1] !== cond) { + let y; + if ($[0] !== cond || $[1] !== value) { t1 = Symbol.for("react.early_return_sentinel"); bb0: { y = [value]; @@ -68,13 +68,13 @@ function useFoo(t0) { } y.push(x); } - $[0] = value; - $[1] = cond; - $[2] = y; - $[3] = t1; + $[0] = cond; + $[1] = value; + $[2] = t1; + $[3] = y; } else { - y = $[2]; - t1 = $[3]; + t1 = $[2]; + y = $[3]; } if (t1 !== Symbol.for("react.early_return_sentinel")) { return t1; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch-escaping.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch-escaping.expect.md index 700df01c5cca5..5e57a460181dd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch-escaping.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch-escaping.expect.md @@ -33,7 +33,7 @@ const { throwInput } = require("shared-runtime"); function Component(props) { const $ = _c(3); let x; - if ($[0] !== props.y || $[1] !== props.e) { + if ($[0] !== props.e || $[1] !== props.y) { try { const y = []; y.push(props.y); @@ -43,8 +43,8 @@ function Component(props) { e.push(props.e); x = e; } - $[0] = props.y; - $[1] = props.e; + $[0] = props.e; + $[1] = props.y; $[2] = x; } else { x = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch.expect.md index c740c7d6b6c1c..921d657e16008 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-try-value-modified-in-catch.expect.md @@ -32,7 +32,7 @@ const { throwInput } = require("shared-runtime"); function Component(props) { const $ = _c(3); let t0; - if ($[0] !== props.y || $[1] !== props.e) { + if ($[0] !== props.e || $[1] !== props.y) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { try { @@ -46,8 +46,8 @@ function Component(props) { break bb0; } } - $[0] = props.y; - $[1] = props.e; + $[0] = props.e; + $[1] = props.y; $[2] = t0; } else { t0 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-catch-param.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-catch-param.expect.md index b04bd5345817b..562c0bc1c86b5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-catch-param.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-catch-param.expect.md @@ -32,8 +32,8 @@ const { throwInput } = require("shared-runtime"); function Component(props) { const $ = _c(2); - let x; let t0; + let x; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -47,11 +47,11 @@ function Component(props) { break bb0; } } - $[0] = x; - $[1] = t0; + $[0] = t0; + $[1] = x; } else { - x = $[0]; - t0 = $[1]; + t0 = $[0]; + x = $[1]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-return.expect.md index af5f2ebfcfea5..71a59aba2f758 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-with-return.expect.md @@ -33,8 +33,8 @@ const { shallowCopy, throwInput } = require("shared-runtime"); function Component(props) { const $ = _c(2); - let x; let t0; + let x; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { @@ -52,11 +52,11 @@ function Component(props) { break bb0; } } - $[0] = x; - $[1] = t0; + $[0] = t0; + $[1] = x; } else { - x = $[0]; - t0 = $[1]; + t0 = $[0]; + x = $[1]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md index 54d5be2d6bf44..c3c45beb86544 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log-default-import.expect.md @@ -78,10 +78,10 @@ export function Component(t0) { t5 = $[5]; } let t6; - if ($[6] !== t5 || $[7] !== item1) { + if ($[6] !== item1 || $[7] !== t5) { t6 = ; - $[6] = t5; - $[7] = item1; + $[6] = item1; + $[7] = t5; $[8] = t6; } else { t6 = $[8]; @@ -95,10 +95,10 @@ export function Component(t0) { t7 = $[10]; } let t8; - if ($[11] !== t7 || $[12] !== item2) { + if ($[11] !== item2 || $[12] !== t7) { t8 = ; - $[11] = t7; - $[12] = item2; + $[11] = item2; + $[12] = t7; $[13] = t8; } else { t8 = $[13]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md index 072c6d03d9adb..4acbd2dfdb3be 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-log.expect.md @@ -76,10 +76,10 @@ export function Component(t0) { t5 = $[5]; } let t6; - if ($[6] !== t5 || $[7] !== item1) { + if ($[6] !== item1 || $[7] !== t5) { t6 = ; - $[6] = t5; - $[7] = item1; + $[6] = item1; + $[7] = t5; $[8] = t6; } else { t6 = $[8]; @@ -93,10 +93,10 @@ export function Component(t0) { t7 = $[10]; } let t8; - if ($[11] !== t7 || $[12] !== item2) { + if ($[11] !== item2 || $[12] !== t7) { t8 = ; - $[11] = t7; - $[12] = item2; + $[11] = item2; + $[12] = t7; $[13] = t8; } else { t8 = $[13]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md index caa74267f326b..5016b0c4dfdfd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture-namespace-import.expect.md @@ -114,10 +114,10 @@ export function Component(t0) { } const t10 = items_0[1]; let t11; - if ($[14] !== t9 || $[15] !== t10) { + if ($[14] !== t10 || $[15] !== t9) { t11 = ; - $[14] = t9; - $[15] = t10; + $[14] = t10; + $[15] = t9; $[16] = t11; } else { t11 = $[16]; @@ -132,16 +132,16 @@ export function Component(t0) { t12 = $[19]; } let t13; - if ($[20] !== t12 || $[21] !== items_0) { + if ($[20] !== items_0 || $[21] !== t12) { t13 = ; - $[20] = t12; - $[21] = items_0; + $[20] = items_0; + $[21] = t12; $[22] = t13; } else { t13 = $[22]; } let t14; - if ($[23] !== t8 || $[24] !== t11 || $[25] !== t13) { + if ($[23] !== t11 || $[24] !== t13 || $[25] !== t8) { t14 = ( <> {t8} @@ -149,9 +149,9 @@ export function Component(t0) { {t13} ); - $[23] = t8; - $[24] = t11; - $[25] = t13; + $[23] = t11; + $[24] = t13; + $[25] = t8; $[26] = t14; } else { t14 = $[26]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md index a92abd4ca597c..3f341fc6650d5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/type-provider-store-capture.expect.md @@ -114,10 +114,10 @@ export function Component(t0) { } const t10 = items_0[1]; let t11; - if ($[14] !== t9 || $[15] !== t10) { + if ($[14] !== t10 || $[15] !== t9) { t11 = ; - $[14] = t9; - $[15] = t10; + $[14] = t10; + $[15] = t9; $[16] = t11; } else { t11 = $[16]; @@ -132,16 +132,16 @@ export function Component(t0) { t12 = $[19]; } let t13; - if ($[20] !== t12 || $[21] !== items_0) { + if ($[20] !== items_0 || $[21] !== t12) { t13 = ; - $[20] = t12; - $[21] = items_0; + $[20] = items_0; + $[21] = t12; $[22] = t13; } else { t13 = $[22]; } let t14; - if ($[23] !== t8 || $[24] !== t11 || $[25] !== t13) { + if ($[23] !== t11 || $[24] !== t13 || $[25] !== t8) { t14 = ( <> {t8} @@ -149,9 +149,9 @@ export function Component(t0) { {t13} ); - $[23] = t8; - $[24] = t11; - $[25] = t13; + $[23] = t11; + $[24] = t13; + $[25] = t8; $[26] = t14; } else { t14 = $[26]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unary-expr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unary-expr.expect.md index fbd13dc1b06b2..7fa86838e8c2a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unary-expr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/unary-expr.expect.md @@ -38,22 +38,22 @@ function component(a) { const f = typeof t.t; let t0; if ( - $[0] !== z || - $[1] !== p || - $[2] !== q || + $[0] !== e || + $[1] !== f || + $[2] !== m || $[3] !== n || - $[4] !== m || - $[5] !== e || - $[6] !== f + $[4] !== p || + $[5] !== q || + $[6] !== z ) { t0 = { z, p, q, n, m, e, f }; - $[0] = z; - $[1] = p; - $[2] = q; + $[0] = e; + $[1] = f; + $[2] = m; $[3] = n; - $[4] = m; - $[5] = e; - $[6] = f; + $[4] = p; + $[5] = q; + $[6] = z; $[7] = t0; } else { t0 = $[7]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-call-expression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-call-expression.expect.md index 663a6788f345b..7f79cae4a0361 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-call-expression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-call-expression.expect.md @@ -89,10 +89,10 @@ function Inner(props) { t2 = $[3]; } let t3; - if ($[4] !== t2 || $[5] !== output) { + if ($[4] !== output || $[5] !== t2) { t3 = ; - $[4] = t2; - $[5] = output; + $[4] = output; + $[5] = t2; $[6] = t3; } else { t3 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md index ffa5f57b437d5..d94a5e7e375b3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-conditional.expect.md @@ -109,10 +109,10 @@ function Inner(props) { t4 = $[3]; } let t5; - if ($[4] !== t4 || $[5] !== output) { + if ($[4] !== output || $[5] !== t4) { t5 = ; - $[4] = t4; - $[5] = output; + $[4] = output; + $[5] = t4; $[6] = t5; } else { t5 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-method-call.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-method-call.expect.md index 99effce93483c..cf0093ea941bf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-method-call.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-operator-method-call.expect.md @@ -91,10 +91,10 @@ function Inner(props) { t2 = $[3]; } let t3; - if ($[4] !== t2 || $[5] !== output) { + if ($[4] !== output || $[5] !== t2) { t3 = ; - $[4] = t2; - $[5] = output; + $[4] = output; + $[5] = t2; $[6] = t3; } else { t3 = $[6]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md index 1292ea14890e1..c3e115fa0d1cf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useEffect-nested-lambdas.expect.md @@ -51,7 +51,7 @@ function Component(props) { } const exit = t0; let t1; - if ($[2] !== item.value || $[3] !== exit) { + if ($[2] !== exit || $[3] !== item.value) { t1 = () => { const cleanup = GlobalEventEmitter.addListener("onInput", () => { if (item.value) { @@ -60,8 +60,8 @@ function Component(props) { }); return () => cleanup.remove(); }; - $[2] = item.value; - $[3] = exit; + $[2] = exit; + $[3] = item.value; $[4] = t1; } else { t1 = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md index b6a4187355c14..28d3e333594a7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useState-unpruned-dependency.expect.md @@ -62,13 +62,13 @@ function Component(props) { {w}
); - let condition = $[2] !== x || $[3] !== w; + let condition = $[2] !== w || $[3] !== x; if (!condition) { let old$t1 = $[4]; $structuralCheck(old$t1, t1, "t1", "Component", "cached", "(7:10)"); } - $[2] = x; - $[3] = w; + $[2] = w; + $[3] = x; $[4] = t1; if (condition) { t1 = ( From fd018af617cf9f8be607f45fc53d6d8167d29eb4 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 19:22:04 -0500 Subject: [PATCH 348/426] [compiler] Delete propagateScopeDeps (non-hir) (#31199) `enablePropagateScopeDepsHIR` is now used extensively in Meta. This has been tested for over two weeks in our e2e tests and production. The rest of this stack deletes `LoweredFunction.dependencies`, which the non-hir version of `PropagateScopeDeps` depends on. To avoid a more forked HIR (non-hir with dependencies and hir with no dependencies), let's go ahead and clean up the non-hir version of PropagateScopeDepsHIR. Note that all fixture changes in this PR were previously reviewed when they were copied to `propagate-scope-deps-hir-fork`. Will clean up / merge these duplicate fixtures in a later PR ' --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31199). * #31202 * #31203 * #31201 * #31200 * #31346 * __->__ #31199 --- .../src/Entrypoint/Pipeline.ts | 24 +- .../src/HIR/Environment.ts | 10 - .../PropagateScopeDependencies.ts | 1324 ----------------- .../src/ReactiveScopes/index.ts | 1 - ...ug-invalid-hoisting-functionexpr.expect.md | 4 +- ...-try-catch-maybe-null-dependency.expect.md | 16 +- .../capturing-func-mutate-2.expect.md | 4 +- .../conditional-break-labeled.expect.md | 18 +- .../conditional-early-return.expect.md | 78 +- .../compiler/conditional-on-mutable.expect.md | 24 +- ...rly-return-within-reactive-scope.expect.md | 26 +- ...rly-return-within-reactive-scope.expect.md | 20 +- ...ession-with-conditional-optional.expect.md | 50 + ...r-expression-with-conditional-optional.js} | 0 ...mber-expression-with-conditional.expect.md | 50 + ...nal-member-expression-with-conditional.js} | 0 ...-optional-call-chain-in-optional.expect.md | 2 +- ...unctionexpr-conditional-access-2.expect.md | 4 +- .../functionexpr-conditional-access-2.tsx | 2 +- ...r\342\200\223conditional-access.expect.md" | 8 +- ...tionexpr\342\200\223conditional-access.js" | 2 +- .../iife-return-modified-later-phi.expect.md | 11 +- ...equential-optional-chain-nonnull.expect.md | 4 +- .../compiler/nested-optional-chains.expect.md | 12 +- ...consequent-alternate-both-return.expect.md | 11 +- ...ession-with-conditional-optional.expect.md | 74 - ...mber-expression-with-conditional.expect.md | 74 - ...rly-return-within-reactive-scope.expect.md | 22 +- ...ence-array-push-consecutive-phis.expect.md | 18 +- .../phi-type-inference-array-push.expect.md | 11 +- ...hi-type-inference-property-store.expect.md | 11 +- ...ack-conditional-access-own-scope.expect.md | 50 + ...eCallback-conditional-access-own-scope.ts} | 0 ...ck-infer-conditional-value-block.expect.md | 59 + ...Callback-infer-conditional-value-block.ts} | 0 ...less-specific-conditional-access.expect.md | 2 + ...ack-conditional-access-own-scope.expect.md | 58 - ...ck-infer-conditional-value-block.expect.md | 63 - ...properties-inside-optional-chain.expect.md | 4 +- ...-in-returned-function-expression.expect.md | 4 +- ...function-cond-access-not-hoisted.expect.md | 4 +- ...e-uncond-optional-chain-and-cond.expect.md | 4 +- .../join-uncond-scopes-cond-deps.expect.md | 15 +- .../promote-uncond.expect.md | 11 +- .../ssa-cascading-eliminated-phis.expect.md | 25 +- .../compiler/ssa-leave-case.expect.md | 11 +- ...ernary-destruction-with-mutation.expect.md | 12 +- ...ssa-renaming-ternary-destruction.expect.md | 11 +- ...a-renaming-ternary-with-mutation.expect.md | 12 +- .../compiler/ssa-renaming-ternary.expect.md | 11 +- ...onditional-ternary-with-mutation.expect.md | 12 +- ...a-renaming-unconditional-ternary.expect.md | 12 +- ...ming-unconditional-with-mutation.expect.md | 12 +- ...-via-destructuring-with-mutation.expect.md | 12 +- .../ssa-renaming-with-mutation.expect.md | 12 +- .../switch-non-final-default.expect.md | 31 +- .../fixtures/compiler/switch.expect.md | 26 +- .../try-catch-mutate-outer-value.expect.md | 16 +- ...-expression-returns-caught-value.expect.md | 4 +- ...ject-method-returns-caught-value.expect.md | 4 +- .../useMemo-multiple-if-else.expect.md | 22 +- 61 files changed, 566 insertions(+), 1868 deletions(-) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{optional-member-expression-with-conditional-optional.js => error.hoist-optional-member-expression-with-conditional-optional.js} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{optional-member-expression-with-conditional.js => error.hoist-optional-member-expression-with-conditional.js} (100%) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/{useCallback-conditional-access-own-scope.ts => error.hoist-useCallback-conditional-access-own-scope.ts} (100%) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/{useCallback-infer-conditional-value-block.ts => error.hoist-useCallback-infer-conditional-value-block.ts} (100%) delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-conditional-access-own-scope.expect.md delete mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-infer-conditional-value-block.expect.md diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 7ae520a144c9b..1127e91029328 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -57,7 +57,6 @@ import { mergeReactiveScopesThatInvalidateTogether, promoteUsedTemporaries, propagateEarlyReturns, - propagateScopeDependencies, pruneHoistedContexts, pruneNonEscapingScopes, pruneNonReactiveDependencies, @@ -348,14 +347,12 @@ function* runWithEnvironment( }); assertTerminalSuccessorsExist(hir); assertTerminalPredsExist(hir); - if (env.config.enablePropagateDepsInHIR) { - propagateScopeDependenciesHIR(hir); - yield log({ - kind: 'hir', - name: 'PropagateScopeDependenciesHIR', - value: hir, - }); - } + propagateScopeDependenciesHIR(hir); + yield log({ + kind: 'hir', + name: 'PropagateScopeDependenciesHIR', + value: hir, + }); if (env.config.inlineJsxTransform) { inlineJsxTransform(hir, env.config.inlineJsxTransform); @@ -383,15 +380,6 @@ function* runWithEnvironment( }); assertScopeInstructionsWithinScopes(reactiveFunction); - if (!env.config.enablePropagateDepsInHIR) { - propagateScopeDependencies(reactiveFunction); - yield log({ - kind: 'reactive', - name: 'PropagateScopeDependencies', - value: reactiveFunction, - }); - } - pruneNonEscapingScopes(reactiveFunction); yield log({ kind: 'reactive', diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 1189f2e125886..1d2e155848802 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -231,16 +231,6 @@ const EnvironmentConfigSchema = z.object({ */ enableUseTypeAnnotations: z.boolean().default(false), - enablePropagateDepsInHIR: z.boolean().default(false), - - /** - * Enables inference of optional dependency chains. Without this flag - * a property chain such as `props?.items?.foo` will infer as a dep on - * just `props`. With this flag enabled, we'll infer that full path as - * the dependency. - */ - enableOptionalDependencies: z.boolean().default(true), - /** * Enables inlining ReactElement object literals in place of JSX * An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts deleted file mode 100644 index dc1142b271e77..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/PropagateScopeDependencies.ts +++ /dev/null @@ -1,1324 +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 {CompilerError} from '../CompilerError'; -import {Environment} from '../HIR'; -import { - areEqualPaths, - BlockId, - DeclarationId, - GeneratedSource, - Identifier, - InstructionId, - InstructionKind, - isObjectMethodType, - isRefValueType, - isUseRefType, - makeInstructionId, - Place, - PrunedReactiveScopeBlock, - ReactiveFunction, - ReactiveInstruction, - ReactiveOptionalCallValue, - ReactiveScope, - ReactiveScopeBlock, - ReactiveScopeDependency, - ReactiveTerminalStatement, - ReactiveValue, - ScopeId, -} from '../HIR/HIR'; -import {eachInstructionValueOperand, eachPatternOperand} from '../HIR/visitors'; -import {empty, Stack} from '../Utils/Stack'; -import {assertExhaustive, Iterable_some} from '../Utils/utils'; -import { - ReactiveScopeDependencyTree, - ReactiveScopePropertyDependency, -} from './DeriveMinimalDependencies'; -import {ReactiveFunctionVisitor, visitReactiveFunction} from './visitors'; - -/* - * Infers the dependencies of each scope to include variables whose values - * are non-stable and created prior to the start of the scope. Also propagates - * dependencies upwards, so that parent scope dependencies are the union of - * their direct dependencies and those of their child scopes. - */ -export function propagateScopeDependencies(fn: ReactiveFunction): void { - const escapingTemporaries: TemporariesUsedOutsideDefiningScope = { - declarations: new Map(), - usedOutsideDeclaringScope: new Set(), - }; - visitReactiveFunction(fn, new FindPromotedTemporaries(), escapingTemporaries); - - const context = new Context(escapingTemporaries.usedOutsideDeclaringScope); - for (const param of fn.params) { - if (param.kind === 'Identifier') { - context.declare(param.identifier, { - id: makeInstructionId(0), - scope: empty(), - }); - } else { - context.declare(param.place.identifier, { - id: makeInstructionId(0), - scope: empty(), - }); - } - } - visitReactiveFunction(fn, new PropagationVisitor(fn.env), context); -} - -type TemporariesUsedOutsideDefiningScope = { - /* - * tracks all relevant temporary declarations (currently LoadLocal and PropertyLoad) - * and the scope where they are defined - */ - declarations: Map; - // temporaries used outside of their defining scope - usedOutsideDeclaringScope: Set; -}; -class FindPromotedTemporaries extends ReactiveFunctionVisitor { - scopes: Array = []; - - override visitScope( - scope: ReactiveScopeBlock, - state: TemporariesUsedOutsideDefiningScope, - ): void { - this.scopes.push(scope.scope.id); - this.traverseScope(scope, state); - this.scopes.pop(); - } - - override visitInstruction( - instruction: ReactiveInstruction, - state: TemporariesUsedOutsideDefiningScope, - ): void { - // Visit all places first, then record temporaries which may need to be promoted - this.traverseInstruction(instruction, state); - - const scope = this.scopes.at(-1); - if (instruction.lvalue === null || scope === undefined) { - return; - } - switch (instruction.value.kind) { - case 'LoadLocal': - case 'LoadContext': - case 'PropertyLoad': { - state.declarations.set( - instruction.lvalue.identifier.declarationId, - scope, - ); - break; - } - default: { - break; - } - } - } - - override visitPlace( - _id: InstructionId, - place: Place, - state: TemporariesUsedOutsideDefiningScope, - ): void { - const declaringScope = state.declarations.get( - place.identifier.declarationId, - ); - if (declaringScope === undefined) { - return; - } - if (this.scopes.indexOf(declaringScope) === -1) { - // Declaring scope is not active === used outside declaring scope - state.usedOutsideDeclaringScope.add(place.identifier.declarationId); - } - } -} - -type DeclMap = Map; -type Decl = { - id: InstructionId; - scope: Stack; -}; - -/** - * TraversalState and PoisonState is used to track the poisoned state of a scope. - * - * A scope is poisoned when either of these conditions hold: - * - one of its own nested blocks is a jump target (for break/continues) - * - it is a outermost scope and contains a throw / return - * - * When a scope is poisoned, all dependencies (from instructions and inner scopes) - * are added as conditionally accessed. - */ -type ScopeTraversalState = { - value: ReactiveScope; - ownBlocks: Stack; -}; - -class PoisonState { - poisonedBlocks: Set = new Set(); - poisonedScopes: Set = new Set(); - isPoisoned: boolean = false; - - constructor( - poisonedBlocks: Set, - poisonedScopes: Set, - isPoisoned: boolean, - ) { - this.poisonedBlocks = poisonedBlocks; - this.poisonedScopes = poisonedScopes; - this.isPoisoned = isPoisoned; - } - - clone(): PoisonState { - return new PoisonState( - new Set(this.poisonedBlocks), - new Set(this.poisonedScopes), - this.isPoisoned, - ); - } - - take(other: PoisonState): PoisonState { - const copy = new PoisonState( - this.poisonedBlocks, - this.poisonedScopes, - this.isPoisoned, - ); - this.poisonedBlocks = other.poisonedBlocks; - this.poisonedScopes = other.poisonedScopes; - this.isPoisoned = other.isPoisoned; - return copy; - } - - merge( - others: Array, - currentScope: ScopeTraversalState | null, - ): void { - for (const other of others) { - for (const id of other.poisonedBlocks) { - this.poisonedBlocks.add(id); - } - for (const id of other.poisonedScopes) { - this.poisonedScopes.add(id); - } - } - this.#invalidate(currentScope); - } - - #invalidate(currentScope: ScopeTraversalState | null): void { - if (currentScope != null) { - if (this.poisonedScopes.has(currentScope.value.id)) { - this.isPoisoned = true; - return; - } else if ( - currentScope.ownBlocks.find(blockId => this.poisonedBlocks.has(blockId)) - ) { - this.isPoisoned = true; - return; - } - } - this.isPoisoned = false; - } - - /** - * Mark a block or scope as poisoned and update the `isPoisoned` flag. - * - * @param targetBlock id of the block which ends non-linear control flow. - * For a break/continue instruction, this is the target block. - * Throw and return instructions have no target and will poison the earliest - * active scope - */ - addPoisonTarget( - target: BlockId | null, - activeScopes: Stack, - ): void { - const currentScope = activeScopes.value; - if (target == null && currentScope != null) { - let cursor = activeScopes; - while (true) { - const next = cursor.pop(); - if (next.value == null) { - const poisonedScope = cursor.value!.value.id; - this.poisonedScopes.add(poisonedScope); - if (poisonedScope === currentScope?.value.id) { - this.isPoisoned = true; - } - break; - } else { - cursor = next; - } - } - } else if (target != null) { - this.poisonedBlocks.add(target); - if ( - !this.isPoisoned && - currentScope?.ownBlocks.find(blockId => blockId === target) - ) { - this.isPoisoned = true; - } - } - } - - /** - * Invoked during traversal when a poisoned scope becomes inactive - * @param id - * @param currentScope - */ - removeMaybePoisonedScope( - id: ScopeId, - currentScope: ScopeTraversalState | null, - ): void { - this.poisonedScopes.delete(id); - this.#invalidate(currentScope); - } - - removeMaybePoisonedBlock( - id: BlockId, - currentScope: ScopeTraversalState | null, - ): void { - this.poisonedBlocks.delete(id); - this.#invalidate(currentScope); - } -} - -class Context { - #temporariesUsedOutsideScope: Set; - #declarations: DeclMap = new Map(); - #reassignments: Map = new Map(); - // Reactive dependencies used in the current reactive scope. - #dependencies: ReactiveScopeDependencyTree = - new ReactiveScopeDependencyTree(); - /* - * We keep a sidemap for temporaries created by PropertyLoads, and do - * not store any control flow (i.e. #inConditionalWithinScope) here. - * - a ReactiveScope (A) containing a PropertyLoad may differ from the - * ReactiveScope (B) that uses the produced temporary. - * - codegen will inline these PropertyLoads back into scope (B) - */ - #properties: Map = new Map(); - #temporaries: Map = new Map(); - #inConditionalWithinScope: boolean = false; - /* - * Reactive dependencies used unconditionally in the current conditional. - * Composed of dependencies: - * - directly accessed within block (added in visitDep) - * - accessed by all cfg branches (added through promoteDeps) - */ - #depsInCurrentConditional: ReactiveScopeDependencyTree = - new ReactiveScopeDependencyTree(); - #scopes: Stack = empty(); - poisonState: PoisonState = new PoisonState(new Set(), new Set(), false); - - constructor(temporariesUsedOutsideScope: Set) { - this.#temporariesUsedOutsideScope = temporariesUsedOutsideScope; - } - - enter(scope: ReactiveScope, fn: () => void): Set { - // Save context of previous scope - const prevInConditional = this.#inConditionalWithinScope; - const previousDependencies = this.#dependencies; - const prevDepsInConditional: ReactiveScopeDependencyTree | null = this - .isPoisoned - ? this.#depsInCurrentConditional - : null; - if (prevDepsInConditional != null) { - this.#depsInCurrentConditional = new ReactiveScopeDependencyTree(); - } - - /* - * Set context for new scope - * A nested scope should add all deps it directly uses as its own - * unconditional deps, regardless of whether the nested scope is itself - * within a conditional - */ - const scopedDependencies = new ReactiveScopeDependencyTree(); - this.#inConditionalWithinScope = false; - this.#dependencies = scopedDependencies; - this.#scopes = this.#scopes.push({ - value: scope, - ownBlocks: empty(), - }); - this.poisonState.isPoisoned = false; - - fn(); - - // Restore context of previous scope - this.#scopes = this.#scopes.pop(); - this.poisonState.removeMaybePoisonedScope(scope.id, this.#scopes.value); - - this.#dependencies = previousDependencies; - this.#inConditionalWithinScope = prevInConditional; - - // Derive minimal dependencies now, since next line may mutate scopedDependencies - const minInnerScopeDependencies = - scopedDependencies.deriveMinimalDependencies(); - - /* - * propagate dependencies upward using the same rules as normal dependency - * collection. child scopes may have dependencies on values created within - * the outer scope, which necessarily cannot be dependencies of the outer - * scope - */ - this.#dependencies.addDepsFromInnerScope( - scopedDependencies, - this.#inConditionalWithinScope || this.isPoisoned, - this.#checkValidDependency.bind(this), - ); - - if (prevDepsInConditional != null) { - // Outer scope is poisoned - prevDepsInConditional.addDepsFromInnerScope( - this.#depsInCurrentConditional, - true, - this.#checkValidDependency.bind(this), - ); - this.#depsInCurrentConditional = prevDepsInConditional; - } - - return minInnerScopeDependencies; - } - - isUsedOutsideDeclaringScope(place: Place): boolean { - return this.#temporariesUsedOutsideScope.has( - place.identifier.declarationId, - ); - } - - /* - * Prints dependency tree to string for debugging. - * @param includeAccesses - * @returns string representation of DependencyTree - */ - printDeps(includeAccesses: boolean = false): string { - return this.#dependencies.printDeps(includeAccesses); - } - - /* - * We track and return unconditional accesses / deps within this conditional. - * If an object property is always used (i.e. in every conditional path), we - * want to promote it to an unconditional access / dependency. - * - * The caller of `enterConditional` is responsible determining for promotion. - * i.e. call promoteDepsFromExhaustiveConditionals to merge returned results. - * - * e.g. we want to mark props.a.b as an unconditional dep here - * if (foo(...)) { - * access(props.a.b); - * } else { - * access(props.a.b); - * } - */ - enterConditional(fn: () => void): ReactiveScopeDependencyTree { - const prevInConditional = this.#inConditionalWithinScope; - const prevUncondAccessed = this.#depsInCurrentConditional; - this.#inConditionalWithinScope = true; - this.#depsInCurrentConditional = new ReactiveScopeDependencyTree(); - fn(); - const result = this.#depsInCurrentConditional; - this.#inConditionalWithinScope = prevInConditional; - this.#depsInCurrentConditional = prevUncondAccessed; - return result; - } - - /* - * Add dependencies from exhaustive CFG paths into the current ReactiveDeps - * tree. If a property is used in every CFG path, it is promoted to an - * unconditional access / dependency here. - * @param depsInConditionals - */ - promoteDepsFromExhaustiveConditionals( - depsInConditionals: Array, - ): void { - this.#dependencies.promoteDepsFromExhaustiveConditionals( - depsInConditionals, - ); - this.#depsInCurrentConditional.promoteDepsFromExhaustiveConditionals( - depsInConditionals, - ); - } - - /* - * Records where a value was declared, and optionally, the scope where the value originated from. - * This is later used to determine if a dependency should be added to a scope; if the current - * scope we are visiting is the same scope where the value originates, it can't be a dependency - * on itself. - */ - declare(identifier: Identifier, decl: Decl): void { - if (!this.#declarations.has(identifier.declarationId)) { - this.#declarations.set(identifier.declarationId, decl); - } - this.#reassignments.set(identifier, decl); - } - - declareTemporary(lvalue: Place, place: Place): void { - this.#temporaries.set(lvalue.identifier, place); - } - - resolveTemporary(place: Place): Place { - return this.#temporaries.get(place.identifier) ?? place; - } - - #getProperty( - object: Place, - property: string, - optional: boolean, - ): ReactiveScopePropertyDependency { - const resolvedObject = this.resolveTemporary(object); - const resolvedDependency = this.#properties.get(resolvedObject.identifier); - let objectDependency: ReactiveScopePropertyDependency; - /* - * (1) Create the base property dependency as either a LoadLocal (from a temporary) - * or a deep copy of an existing property dependency. - */ - if (resolvedDependency === undefined) { - objectDependency = { - identifier: resolvedObject.identifier, - path: [], - }; - } else { - objectDependency = { - identifier: resolvedDependency.identifier, - path: [...resolvedDependency.path], - }; - } - - objectDependency.path.push({property, optional}); - - return objectDependency; - } - - declareProperty( - lvalue: Place, - object: Place, - property: string, - optional: boolean, - ): void { - const nextDependency = this.#getProperty(object, property, optional); - this.#properties.set(lvalue.identifier, nextDependency); - } - - // Checks if identifier is a valid dependency in the current scope - #checkValidDependency(maybeDependency: ReactiveScopeDependency): boolean { - // ref.current access is not a valid dep - if ( - isUseRefType(maybeDependency.identifier) && - maybeDependency.path.at(0)?.property === 'current' - ) { - return false; - } - - // ref value is not a valid dep - if (isRefValueType(maybeDependency.identifier)) { - return false; - } - - /* - * object methods are not deps because they will be codegen'ed back in to - * the object literal. - */ - if (isObjectMethodType(maybeDependency.identifier)) { - return false; - } - - const identifier = maybeDependency.identifier; - /* - * If this operand is used in a scope, has a dynamic value, and was defined - * before this scope, then its a dependency of the scope. - */ - const currentDeclaration = - this.#reassignments.get(identifier) ?? - this.#declarations.get(identifier.declarationId); - const currentScope = this.currentScope.value?.value; - return ( - currentScope != null && - currentDeclaration !== undefined && - currentDeclaration.id < currentScope.range.start && - (currentDeclaration.scope == null || - currentDeclaration.scope.value?.value !== currentScope) - ); - } - - #isScopeActive(scope: ReactiveScope): boolean { - if (this.#scopes === null) { - return false; - } - return this.#scopes.find(state => state.value === scope); - } - - get currentScope(): Stack { - return this.#scopes; - } - - get isPoisoned(): boolean { - return this.poisonState.isPoisoned; - } - - visitOperand(place: Place): void { - const resolved = this.resolveTemporary(place); - /* - * if this operand is a temporary created for a property load, try to resolve it to - * the expanded Place. Fall back to using the operand as-is. - */ - - let dependency: ReactiveScopePropertyDependency = { - identifier: resolved.identifier, - path: [], - }; - if (resolved.identifier.name === null) { - const propertyDependency = this.#properties.get(resolved.identifier); - if (propertyDependency !== undefined) { - dependency = {...propertyDependency}; - } - } - this.visitDependency(dependency); - } - - visitProperty(object: Place, property: string, optional: boolean): void { - const nextDependency = this.#getProperty(object, property, optional); - this.visitDependency(nextDependency); - } - - visitDependency(maybeDependency: ReactiveScopePropertyDependency): void { - /* - * Any value used after its originally defining scope has concluded must be added as an - * output of its defining scope. Regardless of whether its a const or not, - * some later code needs access to the value. If the current - * scope we are visiting is the same scope where the value originates, it can't be a dependency - * on itself. - */ - - /* - * if originalDeclaration is undefined here, then this is a free var - * (all other decls e.g. `let x;` should be initialized in BuildHIR) - */ - const originalDeclaration = this.#declarations.get( - maybeDependency.identifier.declarationId, - ); - if ( - originalDeclaration !== undefined && - originalDeclaration.scope.value !== null - ) { - originalDeclaration.scope.each(scope => { - if ( - !this.#isScopeActive(scope.value) && - // TODO LeaveSSA: key scope.declarations by DeclarationId - !Iterable_some( - scope.value.declarations.values(), - decl => - decl.identifier.declarationId === - maybeDependency.identifier.declarationId, - ) - ) { - scope.value.declarations.set(maybeDependency.identifier.id, { - identifier: maybeDependency.identifier, - scope: originalDeclaration.scope.value!.value, - }); - } - }); - } - - if (this.#checkValidDependency(maybeDependency)) { - const isPoisoned = this.isPoisoned; - this.#depsInCurrentConditional.add(maybeDependency, isPoisoned); - /* - * Add info about this dependency to the existing tree - * We do not try to join/reduce dependencies here due to missing info - */ - this.#dependencies.add( - maybeDependency, - this.#inConditionalWithinScope || isPoisoned, - ); - } - } - - /* - * Record a variable that is declared in some other scope and that is being reassigned in the - * current one as a {@link ReactiveScope.reassignments} - */ - visitReassignment(place: Place): void { - const currentScope = this.currentScope.value?.value; - if ( - currentScope != null && - !Iterable_some( - currentScope.reassignments, - identifier => - identifier.declarationId === place.identifier.declarationId, - ) && - this.#checkValidDependency({identifier: place.identifier, path: []}) - ) { - // TODO LeaveSSA: scope.reassignments should be keyed by declarationid - currentScope.reassignments.add(place.identifier); - } - } - - pushLabeledBlock(id: BlockId): void { - const currentScope = this.#scopes.value; - if (currentScope != null) { - currentScope.ownBlocks = currentScope.ownBlocks.push(id); - } - } - popLabeledBlock(id: BlockId): void { - const currentScope = this.#scopes.value; - if (currentScope != null) { - const last = currentScope.ownBlocks.value; - currentScope.ownBlocks = currentScope.ownBlocks.pop(); - - CompilerError.invariant(last != null && last === id, { - reason: '[PropagateScopeDependencies] Misformed block stack', - loc: GeneratedSource, - }); - } - this.poisonState.removeMaybePoisonedBlock(id, currentScope); - } -} - -class PropagationVisitor extends ReactiveFunctionVisitor { - env: Environment; - - constructor(env: Environment) { - super(); - this.env = env; - } - - override visitScope(scope: ReactiveScopeBlock, context: Context): void { - const scopeDependencies = context.enter(scope.scope, () => { - this.visitBlock(scope.instructions, context); - }); - for (const candidateDep of scopeDependencies) { - if ( - !Iterable_some( - scope.scope.dependencies, - existingDep => - existingDep.identifier.declarationId === - candidateDep.identifier.declarationId && - areEqualPaths(existingDep.path, candidateDep.path), - ) - ) { - scope.scope.dependencies.add(candidateDep); - } - } - /* - * TODO LeaveSSA: fix existing bug with duplicate deps and reassignments - * see fixture ssa-cascading-eliminated-phis, note that we cache `x` - * twice because its both a dep and a reassignment. - * - * for (const reassignment of scope.scope.reassignments) { - * if ( - * Iterable_some( - * scope.scope.dependencies.values(), - * dep => - * dep.identifier.declarationId === reassignment.declarationId && - * dep.path.length === 0, - * ) - * ) { - * scope.scope.reassignments.delete(reassignment); - * } - * } - */ - } - - override visitPrunedScope( - scopeBlock: PrunedReactiveScopeBlock, - context: Context, - ): void { - /* - * NOTE: we explicitly throw away the deps, we only enter() the scope to record its - * declarations - */ - const _scopeDepdencies = context.enter(scopeBlock.scope, () => { - this.visitBlock(scopeBlock.instructions, context); - }); - } - - override visitInstruction( - instruction: ReactiveInstruction, - context: Context, - ): void { - const {id, value, lvalue} = instruction; - this.visitInstructionValue(context, id, value, lvalue); - if (lvalue == null) { - return; - } - context.declare(lvalue.identifier, { - id, - scope: context.currentScope, - }); - } - - extractOptionalProperty( - context: Context, - optionalValue: ReactiveOptionalCallValue, - lvalue: Place, - ): { - lvalue: Place; - object: Place; - property: string; - optional: boolean; - } | null { - const sequence = optionalValue.value; - CompilerError.invariant(sequence.kind === 'SequenceExpression', { - reason: 'Expected OptionalExpression value to be a SequenceExpression', - description: `Found a \`${sequence.kind}\``, - loc: sequence.loc, - }); - /** - * Base case: inner ` "?." ` - *``` - * = OptionalExpression optional=true (`optionalValue` is here) - * Sequence (`sequence` is here) - * t0 = LoadLocal - * Sequence - * t1 = PropertyLoad t0 . - * LoadLocal t1 - * ``` - */ - if ( - sequence.instructions.length === 1 && - sequence.instructions[0].lvalue !== null && - sequence.instructions[0].value.kind === 'LoadLocal' && - sequence.instructions[0].value.place.identifier.name !== null && - !context.isUsedOutsideDeclaringScope(sequence.instructions[0].lvalue) && - sequence.value.kind === 'SequenceExpression' && - sequence.value.instructions.length === 1 && - sequence.value.instructions[0].value.kind === 'PropertyLoad' && - sequence.value.instructions[0].value.object.identifier.id === - sequence.instructions[0].lvalue.identifier.id && - sequence.value.instructions[0].lvalue !== null && - sequence.value.value.kind === 'LoadLocal' && - sequence.value.value.place.identifier.id === - sequence.value.instructions[0].lvalue.identifier.id - ) { - context.declareTemporary( - sequence.instructions[0].lvalue, - sequence.instructions[0].value.place, - ); - const propertyLoad = sequence.value.instructions[0].value; - return { - lvalue, - object: propertyLoad.object, - property: propertyLoad.property, - optional: optionalValue.optional, - }; - } - /** - * Base case 2: inner ` "." "?." - * ``` - * = OptionalExpression optional=true (`optionalValue` is here) - * Sequence (`sequence` is here) - * t0 = Sequence - * t1 = LoadLocal - * ... // see note - * PropertyLoad t1 . - * [46] Sequence - * t2 = PropertyLoad t0 . - * [46] LoadLocal t2 - * ``` - * - * Note that it's possible to have additional inner chained non-optional - * property loads at "...", from an expression like `a?.b.c.d.e`. We could - * expand to support this case by relaxing the check on the inner sequence - * length, ensuring all instructions after the first LoadLocal are PropertyLoad - * and then iterating to ensure that the lvalue of the previous is always - * the object of the next PropertyLoad, w the final lvalue as the object - * of the sequence.value's object. - * - * But this case is likely rare in practice, usually once you're optional - * chaining all property accesses are optional (not `a?.b.c` but `a?.b?.c`). - * Also, HIR-based PropagateScopeDeps will handle this case so it doesn't - * seem worth it to optimize for that edge-case here. - */ - if ( - sequence.instructions.length === 1 && - sequence.instructions[0].lvalue !== null && - sequence.instructions[0].value.kind === 'SequenceExpression' && - sequence.instructions[0].value.instructions.length === 1 && - sequence.instructions[0].value.instructions[0].lvalue !== null && - sequence.instructions[0].value.instructions[0].value.kind === - 'LoadLocal' && - sequence.instructions[0].value.instructions[0].value.place.identifier - .name !== null && - !context.isUsedOutsideDeclaringScope( - sequence.instructions[0].value.instructions[0].lvalue, - ) && - sequence.instructions[0].value.value.kind === 'PropertyLoad' && - sequence.instructions[0].value.value.object.identifier.id === - sequence.instructions[0].value.instructions[0].lvalue.identifier.id && - sequence.value.kind === 'SequenceExpression' && - sequence.value.instructions.length === 1 && - sequence.value.instructions[0].lvalue !== null && - sequence.value.instructions[0].value.kind === 'PropertyLoad' && - sequence.value.instructions[0].value.object.identifier.id === - sequence.instructions[0].lvalue.identifier.id && - sequence.value.value.kind === 'LoadLocal' && - sequence.value.value.place.identifier.id === - sequence.value.instructions[0].lvalue.identifier.id - ) { - // LoadLocal - context.declareTemporary( - sequence.instructions[0].value.instructions[0].lvalue, - sequence.instructions[0].value.instructions[0].value.place, - ); - // PropertyLoad . (the inner non-optional property) - context.declareProperty( - sequence.instructions[0].lvalue, - sequence.instructions[0].value.value.object, - sequence.instructions[0].value.value.property, - false, - ); - const propertyLoad = sequence.value.instructions[0].value; - return { - lvalue, - object: propertyLoad.object, - property: propertyLoad.property, - optional: optionalValue.optional, - }; - } - - /** - * Composed case: - * - ` "." or "?." ` - * - ` "." or "?>" ` - * - * This case is convoluted, note how `t0` appears as an lvalue *twice* - * and then is an operand of an intermediate LoadLocal and then the - * object of the final PropertyLoad: - * - * ``` - * = OptionalExpression optional=false (`optionalValue` is here) - * Sequence (`sequence` is here) - * t0 = Sequence - * t0 = - * - * LoadLocal t0 - * Sequence - * t1 = PropertyLoad t0. - * LoadLocal t1 - * ``` - */ - if ( - sequence.instructions.length === 1 && - sequence.instructions[0].value.kind === 'SequenceExpression' && - sequence.instructions[0].value.instructions.length === 1 && - sequence.instructions[0].value.instructions[0].lvalue !== null && - sequence.instructions[0].value.instructions[0].value.kind === - 'OptionalExpression' && - sequence.instructions[0].value.value.kind === 'LoadLocal' && - sequence.instructions[0].value.value.place.identifier.id === - sequence.instructions[0].value.instructions[0].lvalue.identifier.id && - sequence.value.kind === 'SequenceExpression' && - sequence.value.instructions.length === 1 && - sequence.value.instructions[0].lvalue !== null && - sequence.value.instructions[0].value.kind === 'PropertyLoad' && - sequence.value.instructions[0].value.object.identifier.id === - sequence.instructions[0].value.value.place.identifier.id && - sequence.value.value.kind === 'LoadLocal' && - sequence.value.value.place.identifier.id === - sequence.value.instructions[0].lvalue.identifier.id - ) { - const {lvalue: innerLvalue, value: innerOptional} = - sequence.instructions[0].value.instructions[0]; - const innerProperty = this.extractOptionalProperty( - context, - innerOptional, - innerLvalue, - ); - if (innerProperty === null) { - return null; - } - context.declareProperty( - innerProperty.lvalue, - innerProperty.object, - innerProperty.property, - innerProperty.optional, - ); - const propertyLoad = sequence.value.instructions[0].value; - return { - lvalue, - object: propertyLoad.object, - property: propertyLoad.property, - optional: optionalValue.optional, - }; - } - return null; - } - - visitOptionalExpression( - context: Context, - id: InstructionId, - value: ReactiveOptionalCallValue, - lvalue: Place | null, - ): void { - /** - * If this is the first optional=true optional in a recursive OptionalExpression - * subtree, we check to see if the subtree is of the form: - * ``` - * NestedOptional = - * ` . / ?. ` - * ` . / ?. ` - * ``` - * - * Ie strictly a chain like `foo?.bar?.baz` or `a?.b.c`. If the subtree contains - * any other types of expressions - for example `foo?.[makeKey(a)]` - then this - * will return null and we'll go to the default handling below. - * - * If the tree does match the NestedOptional shape, then we'll have recorded - * a sequence of declareProperty calls, and the final visitProperty call here - * will record that optional chain as a dependency (since we know it's about - * to be referenced via its lvalue which is non-null). - */ - if ( - lvalue !== null && - value.optional && - this.env.config.enableOptionalDependencies - ) { - const inner = this.extractOptionalProperty(context, value, lvalue); - if (inner !== null) { - context.visitProperty(inner.object, inner.property, inner.optional); - return; - } - } - - // Otherwise we treat everything after the optional as conditional - const inner = value.value; - /* - * OptionalExpression value is a SequenceExpression where the instructions - * represent the code prior to the `?` and the final value represents the - * conditional code that follows. - */ - CompilerError.invariant(inner.kind === 'SequenceExpression', { - reason: 'Expected OptionalExpression value to be a SequenceExpression', - description: `Found a \`${value.kind}\``, - loc: value.loc, - suggestions: null, - }); - // Instructions are the unconditionally executed portion before the `?` - for (const instr of inner.instructions) { - this.visitInstruction(instr, context); - } - // The final value is the conditional portion following the `?` - context.enterConditional(() => { - this.visitReactiveValue(context, id, inner.value, null); - }); - } - - visitReactiveValue( - context: Context, - id: InstructionId, - value: ReactiveValue, - lvalue: Place | null, - ): void { - switch (value.kind) { - case 'OptionalExpression': { - this.visitOptionalExpression(context, id, value, lvalue); - break; - } - case 'LogicalExpression': { - this.visitReactiveValue(context, id, value.left, null); - context.enterConditional(() => { - this.visitReactiveValue(context, id, value.right, null); - }); - break; - } - case 'ConditionalExpression': { - this.visitReactiveValue(context, id, value.test, null); - - const consequentDeps = context.enterConditional(() => { - this.visitReactiveValue(context, id, value.consequent, null); - }); - const alternateDeps = context.enterConditional(() => { - this.visitReactiveValue(context, id, value.alternate, null); - }); - context.promoteDepsFromExhaustiveConditionals([ - consequentDeps, - alternateDeps, - ]); - break; - } - case 'SequenceExpression': { - for (const instr of value.instructions) { - this.visitInstruction(instr, context); - } - this.visitInstructionValue(context, id, value.value, null); - break; - } - case 'FunctionExpression': { - if (this.env.config.enableTreatFunctionDepsAsConditional) { - context.enterConditional(() => { - for (const operand of eachInstructionValueOperand(value)) { - context.visitOperand(operand); - } - }); - } else { - for (const operand of eachInstructionValueOperand(value)) { - context.visitOperand(operand); - } - } - break; - } - case 'ReactiveFunctionValue': { - CompilerError.invariant(false, { - reason: `Unexpected ReactiveFunctionValue`, - loc: value.loc, - description: null, - suggestions: null, - }); - } - default: { - for (const operand of eachInstructionValueOperand(value)) { - context.visitOperand(operand); - } - } - } - } - - visitInstructionValue( - context: Context, - id: InstructionId, - value: ReactiveValue, - lvalue: Place | null, - ): void { - if (value.kind === 'LoadLocal' && lvalue !== null) { - if ( - value.place.identifier.name !== null && - lvalue.identifier.name === null && - !context.isUsedOutsideDeclaringScope(lvalue) - ) { - context.declareTemporary(lvalue, value.place); - } else { - context.visitOperand(value.place); - } - } else if (value.kind === 'PropertyLoad') { - if (lvalue !== null && !context.isUsedOutsideDeclaringScope(lvalue)) { - context.declareProperty(lvalue, value.object, value.property, false); - } else { - context.visitProperty(value.object, value.property, false); - } - } else if (value.kind === 'StoreLocal') { - context.visitOperand(value.value); - if (value.lvalue.kind === InstructionKind.Reassign) { - context.visitReassignment(value.lvalue.place); - } - context.declare(value.lvalue.place.identifier, { - id, - scope: context.currentScope, - }); - } else if ( - value.kind === 'DeclareLocal' || - value.kind === 'DeclareContext' - ) { - /* - * Some variables may be declared and never initialized. We need - * to retain (and hoist) these declarations if they are included - * in a reactive scope. One approach is to simply add all `DeclareLocal`s - * as scope declarations. - */ - - /* - * We add context variable declarations here, not at `StoreContext`, since - * context Store / Loads are modeled as reads and mutates to the underlying - * variable reference (instead of through intermediate / inlined temporaries) - */ - context.declare(value.lvalue.place.identifier, { - id, - scope: context.currentScope, - }); - } else if (value.kind === 'Destructure') { - context.visitOperand(value.value); - for (const place of eachPatternOperand(value.lvalue.pattern)) { - if (value.lvalue.kind === InstructionKind.Reassign) { - context.visitReassignment(place); - } - context.declare(place.identifier, { - id, - scope: context.currentScope, - }); - } - } else { - this.visitReactiveValue(context, id, value, lvalue); - } - } - - enterTerminal(stmt: ReactiveTerminalStatement, context: Context): void { - if (stmt.label != null) { - context.pushLabeledBlock(stmt.label.id); - } - const terminal = stmt.terminal; - switch (terminal.kind) { - case 'continue': - case 'break': { - context.poisonState.addPoisonTarget( - terminal.target, - context.currentScope, - ); - break; - } - case 'throw': - case 'return': { - context.poisonState.addPoisonTarget(null, context.currentScope); - break; - } - } - } - exitTerminal(stmt: ReactiveTerminalStatement, context: Context): void { - if (stmt.label != null) { - context.popLabeledBlock(stmt.label.id); - } - } - - override visitTerminal( - stmt: ReactiveTerminalStatement, - context: Context, - ): void { - this.enterTerminal(stmt, context); - const terminal = stmt.terminal; - switch (terminal.kind) { - case 'break': - case 'continue': { - break; - } - case 'return': { - context.visitOperand(terminal.value); - break; - } - case 'throw': { - context.visitOperand(terminal.value); - break; - } - case 'for': { - this.visitReactiveValue(context, terminal.id, terminal.init, null); - this.visitReactiveValue(context, terminal.id, terminal.test, null); - context.enterConditional(() => { - this.visitBlock(terminal.loop, context); - if (terminal.update !== null) { - this.visitReactiveValue( - context, - terminal.id, - terminal.update, - null, - ); - } - }); - break; - } - case 'for-of': { - this.visitReactiveValue(context, terminal.id, terminal.init, null); - context.enterConditional(() => { - this.visitBlock(terminal.loop, context); - }); - break; - } - case 'for-in': { - this.visitReactiveValue(context, terminal.id, terminal.init, null); - context.enterConditional(() => { - this.visitBlock(terminal.loop, context); - }); - break; - } - case 'do-while': { - this.visitBlock(terminal.loop, context); - context.enterConditional(() => { - this.visitReactiveValue(context, terminal.id, terminal.test, null); - }); - break; - } - case 'while': { - this.visitReactiveValue(context, terminal.id, terminal.test, null); - context.enterConditional(() => { - this.visitBlock(terminal.loop, context); - }); - break; - } - case 'if': { - context.visitOperand(terminal.test); - const {consequent, alternate} = terminal; - /* - * Consequent and alternate branches are mutually exclusive, - * so we save and restore the poison state here. - */ - const prevPoisonState = context.poisonState.clone(); - const depsInIf = context.enterConditional(() => { - this.visitBlock(consequent, context); - }); - if (alternate !== null) { - const ifPoisonState = context.poisonState.take(prevPoisonState); - const depsInElse = context.enterConditional(() => { - this.visitBlock(alternate, context); - }); - context.poisonState.merge( - [ifPoisonState], - context.currentScope.value, - ); - context.promoteDepsFromExhaustiveConditionals([depsInIf, depsInElse]); - } - break; - } - case 'switch': { - context.visitOperand(terminal.test); - const isDefaultOnly = - terminal.cases.length === 1 && terminal.cases[0].test == null; - if (isDefaultOnly) { - const case_ = terminal.cases[0]; - if (case_.block != null) { - this.visitBlock(case_.block, context); - break; - } - } - const depsInCases = []; - let foundDefault = false; - /** - * Switch branches are mutually exclusive - */ - const prevPoisonState = context.poisonState.clone(); - const mutExPoisonStates: Array = []; - /* - * This can underestimate unconditional accesses due to the current - * CFG representation for fallthrough. This is safe. It only - * reduces granularity of dependencies. - */ - for (const {test, block} of terminal.cases) { - if (test !== null) { - context.visitOperand(test); - } else { - foundDefault = true; - } - if (block !== undefined) { - mutExPoisonStates.push( - context.poisonState.take(prevPoisonState.clone()), - ); - depsInCases.push( - context.enterConditional(() => { - this.visitBlock(block, context); - }), - ); - } - } - if (foundDefault) { - context.promoteDepsFromExhaustiveConditionals(depsInCases); - } - context.poisonState.merge( - mutExPoisonStates, - context.currentScope.value, - ); - break; - } - case 'label': { - this.visitBlock(terminal.block, context); - break; - } - case 'try': { - this.visitBlock(terminal.block, context); - this.visitBlock(terminal.handler, context); - break; - } - default: { - assertExhaustive( - terminal, - `Unexpected terminal kind \`${(terminal as any).kind}\``, - ); - } - } - this.exitTerminal(stmt, context); - } -} diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/index.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/index.ts index eb778305611cf..8841ae92795c8 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/index.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/index.ts @@ -17,7 +17,6 @@ export {mergeReactiveScopesThatInvalidateTogether} from './MergeReactiveScopesTh export {printReactiveFunction} from './PrintReactiveFunction'; export {promoteUsedTemporaries} from './PromoteUsedTemporaries'; export {propagateEarlyReturns} from './PropagateEarlyReturns'; -export {propagateScopeDependencies} from './PropagateScopeDependencies'; export {pruneAllReactiveScopes} from './PruneAllReactiveScopes'; export {pruneHoistedContexts} from './PruneHoistedContexts'; export {pruneNonEscapingScopes} from './PruneNonEscapingScopes'; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-hoisting-functionexpr.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-hoisting-functionexpr.expect.md index e4e47dfde9e2b..d6331db4e7ea3 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-hoisting-functionexpr.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-invalid-hoisting-functionexpr.expect.md @@ -58,7 +58,7 @@ function Component(t0) { const $ = _c(5); const { obj, isObjNull } = t0; let t1; - if ($[0] !== isObjNull || $[1] !== obj.prop) { + if ($[0] !== isObjNull || $[1] !== obj) { t1 = () => { if (!isObjNull) { return obj.prop; @@ -67,7 +67,7 @@ function Component(t0) { } }; $[0] = isObjNull; - $[1] = obj.prop; + $[1] = obj; $[2] = t1; } else { t1 = $[2]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md index 56ca1f7722e45..839821b349a6f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-try-catch-maybe-null-dependency.expect.md @@ -38,16 +38,24 @@ import { identity } from "shared-runtime"; * try-catch block, as that might throw */ function useFoo(maybeNullObject) { - const $ = _c(2); + const $ = _c(4); let y; - if ($[0] !== maybeNullObject.value.inner) { + if ($[0] !== maybeNullObject) { y = []; try { - y.push(identity(maybeNullObject.value.inner)); + let t0; + if ($[2] !== maybeNullObject.value.inner) { + t0 = identity(maybeNullObject.value.inner); + $[2] = maybeNullObject.value.inner; + $[3] = t0; + } else { + t0 = $[3]; + } + y.push(t0); } catch { y.push("null"); } - $[0] = maybeNullObject.value.inner; + $[0] = maybeNullObject; $[1] = y; } else { y = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md index 53deac41495c6..b31a16da90e3f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/capturing-func-mutate-2.expect.md @@ -37,7 +37,7 @@ function component(a, b) { } const y = t0; let z; - if ($[2] !== a || $[3] !== y.b) { + if ($[2] !== a || $[3] !== y) { z = { a }; const x = function () { z.a = 2; @@ -45,7 +45,7 @@ function component(a, b) { x(); $[2] = a; - $[3] = y.b; + $[3] = y; $[4] = z; } else { z = $[4]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-break-labeled.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-break-labeled.expect.md index 76648c251a101..3f795b604e382 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-break-labeled.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-break-labeled.expect.md @@ -33,9 +33,14 @@ import { c as _c } from "react/compiler-runtime"; /** * props.b *does* influence `a` */ function Component(props) { - const $ = _c(2); + const $ = _c(5); let a; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { a = []; a.push(props.a); bb0: { @@ -47,10 +52,13 @@ function Component(props) { } a.push(props.d); - $[0] = props; - $[1] = a; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; } else { - a = $[1]; + a = $[4]; } return a; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-early-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-early-return.expect.md index 82537902bfa19..5e708b95c6fe9 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-early-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-early-return.expect.md @@ -70,10 +70,10 @@ import { c as _c } from "react/compiler-runtime"; /** * props.b does *not* influence `a` */ function ComponentA(props) { - const $ = _c(3); + const $ = _c(5); let a_DEBUG; let t0; - if ($[0] !== props) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.d) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { a_DEBUG = []; @@ -85,12 +85,14 @@ function ComponentA(props) { a_DEBUG.push(props.d); } - $[0] = props; - $[1] = a_DEBUG; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.d; + $[3] = a_DEBUG; + $[4] = t0; } else { - a_DEBUG = $[1]; - t0 = $[2]; + a_DEBUG = $[3]; + t0 = $[4]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; @@ -102,9 +104,14 @@ function ComponentA(props) { * props.b *does* influence `a` */ function ComponentB(props) { - const $ = _c(2); + const $ = _c(5); let a; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { a = []; a.push(props.a); if (props.b) { @@ -112,10 +119,13 @@ function ComponentB(props) { } a.push(props.d); - $[0] = props; - $[1] = a; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; } else { - a = $[1]; + a = $[4]; } return a; } @@ -124,10 +134,15 @@ function ComponentB(props) { * props.b *does* influence `a`, but only in a way that is never observable */ function ComponentC(props) { - const $ = _c(3); + const $ = _c(6); let a; let t0; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { a = []; @@ -140,12 +155,15 @@ function ComponentC(props) { a.push(props.d); } - $[0] = props; - $[1] = a; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; + $[5] = t0; } else { - a = $[1]; - t0 = $[2]; + a = $[4]; + t0 = $[5]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; @@ -157,10 +175,15 @@ function ComponentC(props) { * props.b *does* influence `a` */ function ComponentD(props) { - const $ = _c(3); + const $ = _c(6); let a; let t0; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d + ) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { a = []; @@ -173,12 +196,15 @@ function ComponentD(props) { a.push(props.d); } - $[0] = props; - $[1] = a; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = a; + $[5] = t0; } else { - a = $[1]; - t0 = $[2]; + a = $[4]; + t0 = $[5]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md index ad638cf28d871..fa8348c200972 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/conditional-on-mutable.expect.md @@ -36,9 +36,9 @@ function mayMutate() {} ```javascript import { c as _c } from "react/compiler-runtime"; function ComponentA(props) { - const $ = _c(2); + const $ = _c(4); let t0; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p1 || $[2] !== props.p2) { const a = []; const b = []; if (b) { @@ -49,18 +49,20 @@ function ComponentA(props) { } t0 = ; - $[0] = props; - $[1] = t0; + $[0] = props.p0; + $[1] = props.p1; + $[2] = props.p2; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } return t0; } function ComponentB(props) { - const $ = _c(2); + const $ = _c(4); let t0; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p1 || $[2] !== props.p2) { const a = []; const b = []; if (mayMutate(b)) { @@ -71,10 +73,12 @@ function ComponentB(props) { } t0 = ; - $[0] = props; - $[1] = t0; + $[0] = props.p0; + $[1] = props.p1; + $[2] = props.p2; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-nested-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-nested-early-return-within-reactive-scope.expect.md index 2d33981f73fd1..68b0122ea92dd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-nested-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-nested-early-return-within-reactive-scope.expect.md @@ -31,9 +31,9 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(5); + const $ = _c(7); let t0; - if ($[0] !== props) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -41,12 +41,12 @@ function Component(props) { x.push(props.a); if (props.b) { let t1; - if ($[2] !== props.b) { + if ($[4] !== props.b) { t1 = [props.b]; - $[2] = props.b; - $[3] = t1; + $[4] = props.b; + $[5] = t1; } else { - t1 = $[3]; + t1 = $[5]; } const y = t1; x.push(y); @@ -58,20 +58,22 @@ function Component(props) { break bb0; } else { let t1; - if ($[4] === Symbol.for("react.memo_cache_sentinel")) { + if ($[6] === Symbol.for("react.memo_cache_sentinel")) { t1 = foo(); - $[4] = t1; + $[6] = t1; } else { - t1 = $[4]; + t1 = $[6]; } t0 = t1; break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-within-reactive-scope.expect.md index 6c3525e9e77eb..31df829e0c203 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/early-return-within-reactive-scope.expect.md @@ -45,9 +45,9 @@ import { c as _c } from "react/compiler-runtime"; import { makeArray } from "shared-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(6); let t0; - if ($[0] !== props) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -57,21 +57,23 @@ function Component(props) { break bb0; } else { let t1; - if ($[2] !== props.b) { + if ($[4] !== props.b) { t1 = makeArray(props.b); - $[2] = props.b; - $[3] = t1; + $[4] = props.b; + $[5] = t1; } else { - t1 = $[3]; + t1 = $[5]; } t0 = t1; break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; + $[3] = t0; } else { - t0 = $[1]; + t0 = $[3]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md new file mode 100644 index 0000000000000..d9c2b599998b7 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + if (props.cond) { + x.push(props?.items); + } + return x; + }, [props?.items, props.cond]); + return ( + + ); +} + +``` + + +## Error + +``` + 2 | import {ValidateMemoization} from 'shared-runtime'; + 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]); + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (4:11) + 12 | return ( + 13 | + 14 | ); +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional-optional.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md new file mode 100644 index 0000000000000..57b7d48facbd5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies +import {ValidateMemoization} from 'shared-runtime'; +function Component(props) { + const data = useMemo(() => { + const x = []; + x.push(props?.items); + if (props.cond) { + x.push(props.items); + } + return x; + }, [props?.items, props.cond]); + return ( + + ); +} + +``` + + +## Error + +``` + 2 | import {ValidateMemoization} from 'shared-runtime'; + 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]); + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (4:11) + 12 | return ( + 13 | + 14 | ); +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.js similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.hoist-optional-member-expression-with-conditional.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-optional.expect.md index 75c5d61d407f0..8bf7f5bc71d0e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-optional.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-optional-call-chain-in-optional.expect.md @@ -25,7 +25,7 @@ export const FIXTURE_ENTRYPONT = { 1 | function useFoo(props: {value: {x: string; y: string} | null}) { 2 | const value = props.value; > 3 | return createArray(value?.x, value?.y)?.join(', '); - | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional test block (3:3) + | ^^^^^^^^ Todo: Unexpected terminal kind `optional` for optional fallthrough block (3:3) 4 | } 5 | 6 | function createArray(...args: Array): Array { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md index 32498e1379206..5614560c6c4dc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.expect.md @@ -2,7 +2,7 @@ ## Input ```javascript -// @enableTreatFunctionDepsAsConditional @enablePropagateDepsInHIR:false +// @enableTreatFunctionDepsAsConditional import {Stringify} from 'shared-runtime'; function Component({props}) { @@ -20,7 +20,7 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @enableTreatFunctionDepsAsConditional @enablePropagateDepsInHIR:false +import { c as _c } from "react/compiler-runtime"; // @enableTreatFunctionDepsAsConditional import { Stringify } from "shared-runtime"; function Component(t0) { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.tsx index 2ede54db5f364..ab3e00f9ba2b1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.tsx +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr-conditional-access-2.tsx @@ -1,4 +1,4 @@ -// @enableTreatFunctionDepsAsConditional @enablePropagateDepsInHIR:false +// @enableTreatFunctionDepsAsConditional import {Stringify} from 'shared-runtime'; function Component({props}) { diff --git "a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" "b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" index 4a62bf6f249bb..c7aa3e3b75446 100644 --- "a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" +++ "b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.expect.md" @@ -2,7 +2,7 @@ ## Input ```javascript -// @enableTreatFunctionDepsAsConditional @enablePropagateDepsInHIR:false +// @enableTreatFunctionDepsAsConditional function Component(props) { function getLength() { return props.bar.length; @@ -21,15 +21,15 @@ export const FIXTURE_ENTRYPOINT = { ## Code ```javascript -import { c as _c } from "react/compiler-runtime"; // @enableTreatFunctionDepsAsConditional @enablePropagateDepsInHIR:false +import { c as _c } from "react/compiler-runtime"; // @enableTreatFunctionDepsAsConditional function Component(props) { const $ = _c(5); let t0; - if ($[0] !== props) { + if ($[0] !== props.bar) { t0 = function getLength() { return props.bar.length; }; - $[0] = props; + $[0] = props.bar; $[1] = t0; } else { t0 = $[1]; diff --git "a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.js" "b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.js" index 9bff3e5cdb53b..6e59fb947d150 100644 --- "a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.js" +++ "b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/functionexpr\342\200\223conditional-access.js" @@ -1,4 +1,4 @@ -// @enableTreatFunctionDepsAsConditional @enablePropagateDepsInHIR:false +// @enableTreatFunctionDepsAsConditional function Component(props) { function getLength() { return props.bar.length; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md index bed1c329f0d10..22f967883b09a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/iife-return-modified-later-phi.expect.md @@ -26,9 +26,9 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(3); let items; - if ($[0] !== props) { + if ($[0] !== props.a || $[1] !== props.cond) { let t0; if (props.cond) { t0 = []; @@ -38,10 +38,11 @@ function Component(props) { items = t0; items?.push(props.a); - $[0] = props; - $[1] = items; + $[0] = props.a; + $[1] = props.cond; + $[2] = items; } else { - items = $[1]; + items = $[2]; } return items; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md index 31e2cadf9f7db..f415c20528bfb 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-sequential-optional-chain-nonnull.expect.md @@ -33,11 +33,11 @@ function useFoo(t0) { const $ = _c(2); const { a } = t0; let x; - if ($[0] !== a.b.c.d) { + if ($[0] !== a.b.c.d.e) { x = []; x.push(a?.b.c?.d.e); x.push(a.b?.c.d?.e); - $[0] = a.b.c.d; + $[0] = a.b.c.d.e; $[1] = x; } else { x = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md index 0acf33b2ed87f..92a24194a359d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/nested-optional-chains.expect.md @@ -120,29 +120,29 @@ function useFoo(t0) { } const x = t1; let t2; - if ($[2] !== prop2?.inner) { + if ($[2] !== prop2?.inner.value) { t2 = identity(prop2?.inner.value)?.toString(); - $[2] = prop2?.inner; + $[2] = prop2?.inner.value; $[3] = t2; } else { t2 = $[3]; } const y = t2; let t3; - if ($[4] !== prop3 || $[5] !== prop4) { + if ($[4] !== prop3 || $[5] !== prop4?.inner) { t3 = prop3?.fn(prop4?.inner.value).toString(); $[4] = prop3; - $[5] = prop4; + $[5] = prop4?.inner; $[6] = t3; } else { t3 = $[6]; } const z = t3; let t4; - if ($[7] !== prop5 || $[8] !== prop6) { + if ($[7] !== prop5 || $[8] !== prop6?.inner) { t4 = prop5?.fn(prop6?.inner.value)?.toString(); $[7] = prop5; - $[8] = prop6; + $[8] = prop6?.inner; $[9] = t4; } else { t4 = $[9]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-mutated-in-consequent-alternate-both-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-mutated-in-consequent-alternate-both-return.expect.md index 8a20f9186b447..b5534114c08a1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-mutated-in-consequent-alternate-both-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/object-mutated-in-consequent-alternate-both-return.expect.md @@ -29,9 +29,9 @@ import { c as _c } from "react/compiler-runtime"; import { makeObject_Primitives } from "shared-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(3); let t0; - if ($[0] !== props) { + if ($[0] !== props.cond || $[1] !== props.value) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const object = makeObject_Primitives(); @@ -45,10 +45,11 @@ function Component(props) { break bb0; } } - $[0] = props; - $[1] = t0; + $[0] = props.cond; + $[1] = props.value; + $[2] = t0; } else { - t0 = $[1]; + t0 = $[2]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md deleted file mode 100644 index 2674d78c997e7..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional-optional.expect.md +++ /dev/null @@ -1,74 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { - const data = useMemo(() => { - const x = []; - x.push(props?.items); - if (props.cond) { - x.push(props?.items); - } - return x; - }, [props?.items, props.cond]); - return ( - - ); -} - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -import { ValidateMemoization } from "shared-runtime"; -function Component(props) { - const $ = _c(9); - - props?.items; - let t0; - let x; - if ($[0] !== props?.items || $[1] !== props.cond) { - x = []; - x.push(props?.items); - if (props.cond) { - x.push(props?.items); - } - $[0] = props?.items; - $[1] = props.cond; - $[2] = x; - } else { - x = $[2]; - } - t0 = x; - const data = t0; - - const t1 = props?.items; - let t2; - if ($[3] !== props.cond || $[4] !== t1) { - t2 = [t1, props.cond]; - $[3] = props.cond; - $[4] = t1; - $[5] = t2; - } else { - t2 = $[5]; - } - let t3; - if ($[6] !== data || $[7] !== t2) { - t3 = ; - $[6] = data; - $[7] = t2; - $[8] = t3; - } else { - t3 = $[8]; - } - return t3; -} - -``` - -### Eval output -(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md deleted file mode 100644 index 1d4a50d2858ea..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/optional-member-expression-with-conditional.expect.md +++ /dev/null @@ -1,74 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -import {ValidateMemoization} from 'shared-runtime'; -function Component(props) { - const data = useMemo(() => { - const x = []; - x.push(props?.items); - if (props.cond) { - x.push(props.items); - } - return x; - }, [props?.items, props.cond]); - return ( - - ); -} - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees @enableOptionalDependencies -import { ValidateMemoization } from "shared-runtime"; -function Component(props) { - const $ = _c(9); - - props?.items; - let t0; - let x; - if ($[0] !== props?.items || $[1] !== props.cond) { - x = []; - x.push(props?.items); - if (props.cond) { - x.push(props.items); - } - $[0] = props?.items; - $[1] = props.cond; - $[2] = x; - } else { - x = $[2]; - } - t0 = x; - const data = t0; - - const t1 = props?.items; - let t2; - if ($[3] !== props.cond || $[4] !== t1) { - t2 = [t1, props.cond]; - $[3] = props.cond; - $[4] = t1; - $[5] = t2; - } else { - t2 = $[5]; - } - let t3; - if ($[6] !== data || $[7] !== t2) { - t3 = ; - $[6] = data; - $[7] = t2; - $[8] = t3; - } else { - t3 = $[8]; - } - return t3; -} - -``` - -### Eval output -(kind: exception) Fixture not implemented \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md index 42b3b21a20903..87c9485d99a4e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/partial-early-return-within-reactive-scope.expect.md @@ -30,10 +30,10 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(6); let t0; let y; - if ($[0] !== props) { + if ($[0] !== props.a || $[1] !== props.b || $[2] !== props.cond) { t0 = Symbol.for("react.early_return_sentinel"); bb0: { const x = []; @@ -43,11 +43,11 @@ function Component(props) { break bb0; } else { let t1; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + if ($[5] === Symbol.for("react.memo_cache_sentinel")) { t1 = foo(); - $[3] = t1; + $[5] = t1; } else { - t1 = $[3]; + t1 = $[5]; } y = t1; if (props.b) { @@ -56,12 +56,14 @@ function Component(props) { } } } - $[0] = props; - $[1] = t0; - $[2] = y; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; + $[3] = t0; + $[4] = y; } else { - t0 = $[1]; - y = $[2]; + t0 = $[3]; + y = $[4]; } if (t0 !== Symbol.for("react.early_return_sentinel")) { return t0; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push-consecutive-phis.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push-consecutive-phis.expect.md index f17bcc92cb7ce..16edbf2e23690 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push-consecutive-phis.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push-consecutive-phis.expect.md @@ -49,7 +49,7 @@ import { c as _c } from "react/compiler-runtime"; import { makeArray } from "shared-runtime"; function Component(props) { - const $ = _c(3); + const $ = _c(6); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -59,7 +59,12 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props) { + if ( + $[1] !== props.cond || + $[2] !== props.cond2 || + $[3] !== props.value || + $[4] !== props.value2 + ) { let y; if (props.cond) { if (props.cond2) { @@ -74,10 +79,13 @@ function Component(props) { y.push(x); t1 = [x, y]; - $[1] = props; - $[2] = t1; + $[1] = props.cond; + $[2] = props.cond2; + $[3] = props.value; + $[4] = props.value2; + $[5] = t1; } else { - t1 = $[2]; + t1 = $[5]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push.expect.md index f58eed10fda5a..58e2c8f869a6a 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-array-push.expect.md @@ -36,7 +36,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(3); + const $ = _c(4); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -46,7 +46,7 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props) { + if ($[1] !== props.cond || $[2] !== props.value) { let y; if (props.cond) { y = [props.value]; @@ -57,10 +57,11 @@ function Component(props) { y.push(x); t1 = [x, y]; - $[1] = props; - $[2] = t1; + $[1] = props.cond; + $[2] = props.value; + $[3] = t1; } else { - t1 = $[2]; + t1 = $[3]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-property-store.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-property-store.expect.md index 70551c8e9d7b0..9223c61200128 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-property-store.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/phi-type-inference-property-store.expect.md @@ -32,7 +32,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; // @debug function Component(props) { - const $ = _c(3); + const $ = _c(4); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = {}; @@ -42,7 +42,7 @@ function Component(props) { } const x = t0; let t1; - if ($[1] !== props) { + if ($[1] !== props.a || $[2] !== props.cond) { let y; if (props.cond) { y = {}; @@ -53,10 +53,11 @@ function Component(props) { y.x = x; t1 = [x, y]; - $[1] = props; - $[2] = t1; + $[1] = props.a; + $[2] = props.cond; + $[3] = t1; } else { - t1 = $[2]; + t1 = $[3]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md new file mode 100644 index 0000000000000..8579b773e6218 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.expect.md @@ -0,0 +1,50 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {useCallback} from 'react'; + +function Component({propA, propB}) { + return useCallback(() => { + if (propA) { + return { + value: propB.x.y, + }; + } + }, [propA, propB.x.y]); +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{propA: 1, propB: {x: {y: []}}}], +}; + +``` + + +## Error + +``` + 3 | + 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]); + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (5:11) + 12 | } + 13 | + 14 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-conditional-access-own-scope.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.ts similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-conditional-access-own-scope.ts rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-conditional-access-own-scope.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md new file mode 100644 index 0000000000000..e77e79fd98e0e --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.expect.md @@ -0,0 +1,59 @@ + +## Input + +```javascript +// @validatePreserveExistingMemoizationGuarantees +import {useCallback} from 'react'; +import {identity, mutate} from 'shared-runtime'; + +function useHook(propA, propB) { + return useCallback(() => { + const x = {}; + if (identity(null) ?? propA.a) { + mutate(x); + return { + value: propB.x.y, + }; + } + }, [propA.a, propB.x.y]); +} + +export const FIXTURE_ENTRYPOINT = { + fn: useHook, + params: [{a: 1}, {x: {y: 3}}], +}; + +``` + + +## Error + +``` + 4 | + 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]); + | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14) + +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14) + 15 | } + 16 | + 17 | export const FIXTURE_ENTRYPOINT = { +``` + + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-infer-conditional-value-block.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.ts similarity index 100% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-infer-conditional-value-block.ts rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.hoist-useCallback-infer-conditional-value-block.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md index 940b3975c160d..955d391f912cf 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/error.useCallback-infer-less-specific-conditional-access.expect.md @@ -44,6 +44,8 @@ function Component({propA, propB}) { | ^^^^^^^^^^^^^^^^^ > 14 | }, [propA?.a, propB.x.y]); | ^^^^ CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14) + +CannotPreserveMemoization: React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected (6:14) 15 | } 16 | ``` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-conditional-access-own-scope.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-conditional-access-own-scope.expect.md deleted file mode 100644 index a90492f7a1774..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-conditional-access-own-scope.expect.md +++ /dev/null @@ -1,58 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees -import {useCallback} from 'react'; - -function Component({propA, propB}) { - return useCallback(() => { - if (propA) { - return { - value: propB.x.y, - }; - } - }, [propA, propB.x.y]); -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{propA: 1, propB: {x: {y: []}}}], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees -import { useCallback } from "react"; - -function Component(t0) { - const $ = _c(3); - const { propA, propB } = t0; - let t1; - if ($[0] !== propA || $[1] !== propB.x.y) { - t1 = () => { - if (propA) { - return { value: propB.x.y }; - } - }; - $[0] = propA; - $[1] = propB.x.y; - $[2] = t1; - } else { - t1 = $[2]; - } - return t1; -} - -export const FIXTURE_ENTRYPOINT = { - fn: Component, - params: [{ propA: 1, propB: { x: { y: [] } } }], -}; - -``` - -### Eval output -(kind: ok) "[[ function params=0 ]]" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-infer-conditional-value-block.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-infer-conditional-value-block.expect.md deleted file mode 100644 index d6c01643f5e31..0000000000000 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-infer-conditional-value-block.expect.md +++ /dev/null @@ -1,63 +0,0 @@ - -## Input - -```javascript -// @validatePreserveExistingMemoizationGuarantees -import {useCallback} from 'react'; -import {identity, mutate} from 'shared-runtime'; - -function useHook(propA, propB) { - return useCallback(() => { - const x = {}; - if (identity(null) ?? propA.a) { - mutate(x); - return { - value: propB.x.y, - }; - } - }, [propA.a, propB.x.y]); -} - -export const FIXTURE_ENTRYPOINT = { - fn: useHook, - params: [{a: 1}, {x: {y: 3}}], -}; - -``` - -## Code - -```javascript -import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMemoizationGuarantees -import { useCallback } from "react"; -import { identity, mutate } from "shared-runtime"; - -function useHook(propA, propB) { - const $ = _c(3); - let t0; - if ($[0] !== propA.a || $[1] !== propB.x.y) { - t0 = () => { - const x = {}; - if (identity(null) ?? propA.a) { - mutate(x); - return { value: propB.x.y }; - } - }; - $[0] = propA.a; - $[1] = propB.x.y; - $[2] = t0; - } else { - t0 = $[2]; - } - return t0; -} - -export const FIXTURE_ENTRYPOINT = { - fn: useHook, - params: [{ a: 1 }, { x: { y: 3 } }], -}; - -``` - -### Eval output -(kind: ok) "[[ function params=0 ]]" \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md index 12a84b14f449a..896a547fec25c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reactive-dependencies-non-optional-properties-inside-optional-chain.expect.md @@ -15,9 +15,9 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(2); let t0; - if ($[0] !== props.post.feedback.comments) { + if ($[0] !== props.post.feedback.comments?.edges) { t0 = props.post.feedback.comments?.edges?.map(render); - $[0] = props.post.feedback.comments; + $[0] = props.post.feedback.comments?.edges; $[1] = t0; } else { t0 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassigned-phi-in-returned-function-expression.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassigned-phi-in-returned-function-expression.expect.md index 5c6c680e05e91..39ce103cca071 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassigned-phi-in-returned-function-expression.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reassigned-phi-in-returned-function-expression.expect.md @@ -23,7 +23,7 @@ import { c as _c } from "react/compiler-runtime"; function Component(props) { const $ = _c(2); let t0; - if ($[0] !== props.str) { + if ($[0] !== props) { t0 = () => { let str; if (arguments.length) { @@ -34,7 +34,7 @@ function Component(props) { global.log(str); }; - $[0] = props.str; + $[0] = props; $[1] = t0; } else { t0 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md index 18e9faf63b5dc..f68c826507207 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted.expect.md @@ -38,7 +38,7 @@ function Foo(t0) { const $ = _c(3); const { a, shouldReadA } = t0; let t1; - if ($[0] !== a.b.c || $[1] !== shouldReadA) { + if ($[0] !== a || $[1] !== shouldReadA) { t1 = ( { @@ -50,7 +50,7 @@ function Foo(t0) { shouldInvokeFns={true} /> ); - $[0] = a.b.c; + $[0] = a; $[1] = shouldReadA; $[2] = t1; } else { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md index 9a95e7dc875b4..fa265ae1f8d74 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond.expect.md @@ -65,12 +65,12 @@ function useFoo(t0) { const $ = _c(2); const { screen } = t0; let t1; - if ($[0] !== screen?.title_text) { + if ($[0] !== screen) { t1 = screen?.title_text != null ? "(not null)" : identity({ title: screen.title_text }); - $[0] = screen?.title_text; + $[0] = screen; $[1] = t1; } else { t1 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/join-uncond-scopes-cond-deps.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/join-uncond-scopes-cond-deps.expect.md index c54d0828ecefe..37d347cd9a0b4 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/join-uncond-scopes-cond-deps.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/join-uncond-scopes-cond-deps.expect.md @@ -61,20 +61,13 @@ import { c as _c } from "react/compiler-runtime"; // This tests an optimization, import { CONST_TRUE, setProperty } from "shared-runtime"; function useJoinCondDepsInUncondScopes(props) { - const $ = _c(4); + const $ = _c(2); let t0; if ($[0] !== props.a.b) { const y = {}; - let x; - if ($[2] !== props) { - x = {}; - if (CONST_TRUE) { - setProperty(x, props.a.b); - } - $[2] = props; - $[3] = x; - } else { - x = $[3]; + const x = {}; + if (CONST_TRUE) { + setProperty(x, props.a.b); } setProperty(y, props.a.b); diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md index d3a61a1019c4b..83e050da29fc0 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/reduce-reactive-deps/promote-uncond.expect.md @@ -34,19 +34,20 @@ import { identity } from "shared-runtime"; // and promote it to an unconditional dependency. function usePromoteUnconditionalAccessToDependency(props, other) { - const $ = _c(3); + const $ = _c(4); let x; - if ($[0] !== other || $[1] !== props.a) { + if ($[0] !== other || $[1] !== props.a.a.a || $[2] !== props.a.b) { x = {}; x.a = props.a.a.a; if (identity(other)) { x.c = props.a.b.c; } $[0] = other; - $[1] = props.a; - $[2] = x; + $[1] = props.a.a.a; + $[2] = props.a.b; + $[3] = x; } else { - x = $[2]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-cascading-eliminated-phis.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-cascading-eliminated-phis.expect.md index 6af0cf0af7bca..c39b85e5ba636 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-cascading-eliminated-phis.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-cascading-eliminated-phis.expect.md @@ -36,10 +36,16 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(4); + const $ = _c(7); let x = 0; let values; - if ($[0] !== props || $[1] !== x) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.c || + $[3] !== props.d || + $[4] !== x + ) { values = []; const y = props.a || props.b; values.push(y); @@ -53,13 +59,16 @@ function Component(props) { } values.push(x); - $[0] = props; - $[1] = x; - $[2] = values; - $[3] = x; + $[0] = props.a; + $[1] = props.b; + $[2] = props.c; + $[3] = props.d; + $[4] = x; + $[5] = values; + $[6] = x; } else { - values = $[2]; - x = $[3]; + values = $[5]; + x = $[6]; } return values; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md index a10ad5fae4108..dd61d1fee1280 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-leave-case.expect.md @@ -39,9 +39,9 @@ import { c as _c } from "react/compiler-runtime"; import { Stringify } from "shared-runtime"; function Component(props) { - const $ = _c(2); + const $ = _c(3); let t0; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p1) { const x = []; let y; if (props.p0) { @@ -55,10 +55,11 @@ function Component(props) { {y} ); - $[0] = props; - $[1] = t0; + $[0] = props.p0; + $[1] = props.p1; + $[2] = t0; } else { - t0 = $[1]; + t0 = $[2]; } return t0; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction-with-mutation.expect.md index 3e7fd4bf5f859..c6c7489a4e66d 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction-with-mutation.expect.md @@ -31,17 +31,19 @@ import { c as _c } from "react/compiler-runtime"; import { mutate } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { x = []; x.push(props.bar); props.cond ? (([x] = [[]]), x.push(props.foo)) : null; mutate(x); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction.expect.md index 9b3aad524ce14..693b94d886ce2 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-destruction.expect.md @@ -26,7 +26,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function useFoo(props) { - const $ = _c(4); + const $ = _c(5); let x; if ($[0] !== props.bar) { x = []; @@ -36,12 +36,13 @@ function useFoo(props) { } else { x = $[1]; } - if ($[2] !== props) { + if ($[2] !== props.cond || $[3] !== props.foo) { props.cond ? (([x] = [[]]), x.push(props.foo)) : null; - $[2] = props; - $[3] = x; + $[2] = props.cond; + $[3] = props.foo; + $[4] = x; } else { - x = $[3]; + x = $[4]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-with-mutation.expect.md index de9466c4daa9d..283e55630b898 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary-with-mutation.expect.md @@ -31,17 +31,19 @@ import { c as _c } from "react/compiler-runtime"; import { mutate } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { x = []; x.push(props.bar); props.cond ? ((x = []), x.push(props.foo)) : null; mutate(x); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary.expect.md index e199863257bfe..97cfa052aff98 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-ternary.expect.md @@ -26,7 +26,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function useFoo(props) { - const $ = _c(4); + const $ = _c(5); let x; if ($[0] !== props.bar) { x = []; @@ -36,12 +36,13 @@ function useFoo(props) { } else { x = $[1]; } - if ($[2] !== props) { + if ($[2] !== props.cond || $[3] !== props.foo) { props.cond ? ((x = []), x.push(props.foo)) : null; - $[2] = props; - $[3] = x; + $[2] = props.cond; + $[3] = props.foo; + $[4] = x; } else { - x = $[3]; + x = $[4]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary-with-mutation.expect.md index 16981f69cda90..1c4b48cb7c40f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary-with-mutation.expect.md @@ -31,17 +31,19 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; import { arrayPush } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { x = []; x.push(props.bar); props.cond ? ((x = []), x.push(props.foo)) : ((x = []), x.push(props.bar)); arrayPush(x, 4); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary.expect.md index 99b50ac231342..58723f9fa0b91 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-ternary.expect.md @@ -28,7 +28,7 @@ export const FIXTURE_ENTRYPOINT = { ```javascript import { c as _c } from "react/compiler-runtime"; function useFoo(props) { - const $ = _c(4); + const $ = _c(6); let x; if ($[0] !== props.bar) { x = []; @@ -38,12 +38,14 @@ function useFoo(props) { } else { x = $[1]; } - if ($[2] !== props) { + if ($[2] !== props.bar || $[3] !== props.cond || $[4] !== props.foo) { props.cond ? ((x = []), x.push(props.foo)) : ((x = []), x.push(props.bar)); - $[2] = props; - $[3] = x; + $[2] = props.bar; + $[3] = props.cond; + $[4] = props.foo; + $[5] = x; } else { - x = $[3]; + x = $[5]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-with-mutation.expect.md index f4689e5795552..9f1e21d7c7497 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-unconditional-with-mutation.expect.md @@ -39,9 +39,9 @@ import { c as _c } from "react/compiler-runtime"; import { mutate } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { x = []; x.push(props.bar); if (props.cond) { @@ -53,10 +53,12 @@ function useFoo(props) { } mutate(x); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-via-destructuring-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-via-destructuring-with-mutation.expect.md index ed1056c47c0f8..81cc777522bca 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-via-destructuring-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-via-destructuring-with-mutation.expect.md @@ -35,9 +35,9 @@ import { c as _c } from "react/compiler-runtime"; import { mutate } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { ({ x } = { x: [] }); x.push(props.bar); if (props.cond) { @@ -46,10 +46,12 @@ function useFoo(props) { } mutate(x); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-with-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-with-mutation.expect.md index 26cd73a82b53f..f48cec2c238ba 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-with-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssa-renaming-with-mutation.expect.md @@ -35,9 +35,9 @@ import { c as _c } from "react/compiler-runtime"; import { mutate } from "shared-runtime"; function useFoo(props) { - const $ = _c(2); + const $ = _c(4); let x; - if ($[0] !== props) { + if ($[0] !== props.bar || $[1] !== props.cond || $[2] !== props.foo) { x = []; x.push(props.bar); if (props.cond) { @@ -46,10 +46,12 @@ function useFoo(props) { } mutate(x); - $[0] = props; - $[1] = x; + $[0] = props.bar; + $[1] = props.cond; + $[2] = props.foo; + $[3] = x; } else { - x = $[1]; + x = $[3]; } return x; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md index 788109636b680..804acfce19b48 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch-non-final-default.expect.md @@ -33,10 +33,10 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(7); + const $ = _c(8); let t0; let y; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p2) { const x = []; bb0: switch (props.p0) { case 1: { @@ -45,11 +45,11 @@ function Component(props) { case true: { x.push(props.p2); let t1; - if ($[3] === Symbol.for("react.memo_cache_sentinel")) { + if ($[4] === Symbol.for("react.memo_cache_sentinel")) { t1 = []; - $[3] = t1; + $[4] = t1; } else { - t1 = $[3]; + t1 = $[4]; } y = t1; } @@ -62,23 +62,24 @@ function Component(props) { } t0 = ; - $[0] = props; - $[1] = t0; - $[2] = y; + $[0] = props.p0; + $[1] = props.p2; + $[2] = t0; + $[3] = y; } else { - t0 = $[1]; - y = $[2]; + t0 = $[2]; + y = $[3]; } const child = t0; y.push(props.p4); let t1; - if ($[4] !== child || $[5] !== y) { + if ($[5] !== child || $[6] !== y) { t1 = {child}; - $[4] = child; - $[5] = y; - $[6] = t1; + $[5] = child; + $[6] = y; + $[7] = t1; } else { - t1 = $[6]; + t1 = $[7]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md index 2628982655deb..33a7ae3193053 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/switch.expect.md @@ -28,10 +28,10 @@ function Component(props) { ```javascript import { c as _c } from "react/compiler-runtime"; function Component(props) { - const $ = _c(6); + const $ = _c(8); let t0; let y; - if ($[0] !== props) { + if ($[0] !== props.p0 || $[1] !== props.p2 || $[2] !== props.p3) { const x = []; switch (props.p0) { case true: { @@ -44,23 +44,25 @@ function Component(props) { } t0 = ; - $[0] = props; - $[1] = t0; - $[2] = y; + $[0] = props.p0; + $[1] = props.p2; + $[2] = props.p3; + $[3] = t0; + $[4] = y; } else { - t0 = $[1]; - y = $[2]; + t0 = $[3]; + y = $[4]; } const child = t0; y.push(props.p4); let t1; - if ($[3] !== child || $[4] !== y) { + if ($[5] !== child || $[6] !== y) { t1 = {child}; - $[3] = child; - $[4] = y; - $[5] = t1; + $[5] = child; + $[6] = y; + $[7] = t1; } else { - t1 = $[5]; + t1 = $[7]; } return t1; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-mutate-outer-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-mutate-outer-value.expect.md index 856d1326407ab..cab72226d27ef 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-mutate-outer-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-mutate-outer-value.expect.md @@ -28,9 +28,9 @@ import { c as _c } from "react/compiler-runtime"; const { shallowCopy, throwErrorWithMessage } = require("shared-runtime"); function Component(props) { - const $ = _c(3); + const $ = _c(5); let x; - if ($[0] !== props.a) { + if ($[0] !== props) { x = []; try { let t0; @@ -42,9 +42,17 @@ function Component(props) { } x.push(t0); } catch { - x.push(shallowCopy({ a: props.a })); + let t0; + if ($[3] !== props.a) { + t0 = shallowCopy({ a: props.a }); + $[3] = props.a; + $[4] = t0; + } else { + t0 = $[4]; + } + x.push(t0); } - $[0] = props.a; + $[0] = props; $[1] = x; } else { x = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md index f2e46a6aff315..db8877f061bc1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-function-expression-returns-caught-value.expect.md @@ -31,7 +31,7 @@ import { throwInput } from "shared-runtime"; function Component(props) { const $ = _c(4); let t0; - if ($[0] !== props.value) { + if ($[0] !== props) { t0 = () => { try { throwInput([props.value]); @@ -40,7 +40,7 @@ function Component(props) { return e; } }; - $[0] = props.value; + $[0] = props; $[1] = t0; } else { t0 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md index 83f97ff6cbfbc..b760716a0c72f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/try-catch-within-object-method-returns-caught-value.expect.md @@ -33,7 +33,7 @@ import { throwInput } from "shared-runtime"; function Component(props) { const $ = _c(2); let t0; - if ($[0] !== props.value) { + if ($[0] !== props) { const object = { foo() { try { @@ -46,7 +46,7 @@ function Component(props) { }; t0 = object.foo(); - $[0] = props.value; + $[0] = props; $[1] = t0; } else { t0 = $[1]; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md index 05e465000d6cd..23b05b548221f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/useMemo-multiple-if-else.expect.md @@ -33,11 +33,16 @@ import { c as _c } from "react/compiler-runtime"; import { useMemo } from "react"; function Component(props) { - const $ = _c(3); + const $ = _c(6); let t0; bb0: { let y; - if ($[0] !== props) { + if ( + $[0] !== props.a || + $[1] !== props.b || + $[2] !== props.cond || + $[3] !== props.cond2 + ) { y = []; if (props.cond) { y.push(props.a); @@ -48,12 +53,15 @@ function Component(props) { } y.push(props.b); - $[0] = props; - $[1] = y; - $[2] = t0; + $[0] = props.a; + $[1] = props.b; + $[2] = props.cond; + $[3] = props.cond2; + $[4] = y; + $[5] = t0; } else { - y = $[1]; - t0 = $[2]; + y = $[4]; + t0 = $[5]; } t0 = y; } From c3570b158d087eb4e3ee5748c4bd9360045c8a26 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 5 Nov 2024 19:25:05 -0500 Subject: [PATCH 349/426] [compiler] Collect temporaries and optional chains from inner functions (#31346) Recursively collect identifier / property loads and optional chains from inner functions. This PR is in preparation for #31200 Previously, we only did this in `collectHoistablePropertyLoads` to understand hoistable property loads from inner functions. 1. collectTemporariesSidemap 2. collectOptionalChainSidemap 3. collectHoistablePropertyLoads - ^ this recursively calls `collectTemporariesSidemap`, `collectOptionalChainSidemap`, and `collectOptionalChainSidemap` on inner functions 4. collectDependencies Now, we have 1. collectTemporariesSidemap - recursively record identifiers in inner functions. Note that we track all temporaries in the same map as `IdentifierIds` are currently unique across functions 2. collectOptionalChainSidemap - recursively records optional chain sidemaps in inner functions 3. collectHoistablePropertyLoads - (unchanged, except to remove recursive collection of temporaries) 4. collectDependencies - unchanged: to be modified to recursively collect dependencies in next PR ' --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31346). * #31202 * #31203 * #31201 * #31200 * __->__ #31346 * #31199 --- .../src/HIR/CollectHoistablePropertyLoads.ts | 9 -- .../HIR/CollectOptionalChainDependencies.ts | 66 +++++++---- .../src/HIR/PropagateScopeDependenciesHIR.ts | 110 ++++++++++++++---- .../src/HIR/visitors.ts | 8 ++ 4 files changed, 139 insertions(+), 54 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts index 456425aecaae9..d3c919a6d8afe 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectHoistablePropertyLoads.ts @@ -8,7 +8,6 @@ import { Set_union, getOrInsertDefault, } from '../Utils/utils'; -import {collectOptionalChainSidemap} from './CollectOptionalChainDependencies'; import { BasicBlock, BlockId, @@ -22,7 +21,6 @@ import { ReactiveScopeDependency, ScopeId, } from './HIR'; -import {collectTemporariesSidemap} from './PropagateScopeDependenciesHIR'; const DEBUG_PRINT = false; @@ -373,17 +371,10 @@ function collectNonNullsInBlocks( !fn.env.config.enableTreatFunctionDepsAsConditional ) { const innerFn = instr.value.loweredFunc; - const innerTemporaries = collectTemporariesSidemap( - innerFn.func, - new Set(), - ); - const innerOptionals = collectOptionalChainSidemap(innerFn.func); const innerHoistableMap = collectHoistablePropertyLoadsImpl( innerFn.func, { ...context, - temporaries: innerTemporaries, // TODO: remove in later PR - hoistableFromOptionals: innerOptionals.hoistableObjects, // TODO: remove in later PR nestedFnImmutableContext: context.nestedFnImmutableContext ?? new Set( diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts index 453294784246f..2b7c9f2134e71 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/CollectOptionalChainDependencies.ts @@ -3,7 +3,6 @@ import {assertNonNull} from './CollectHoistablePropertyLoads'; import { BlockId, BasicBlock, - InstructionId, IdentifierId, ReactiveScopeDependency, BranchTerminal, @@ -15,6 +14,8 @@ import { OptionalTerminal, HIRFunction, DependencyPathEntry, + Instruction, + Terminal, } from './HIR'; import {printIdentifier} from './PrintHIR'; @@ -22,25 +23,14 @@ export function collectOptionalChainSidemap( fn: HIRFunction, ): OptionalChainSidemap { const context: OptionalTraversalContext = { + currFn: fn, blocks: fn.body.blocks, seenOptionals: new Set(), processedInstrsInOptional: new Set(), temporariesReadInOptional: new Map(), hoistableObjects: new Map(), }; - for (const [_, block] of fn.body.blocks) { - if ( - block.terminal.kind === 'optional' && - !context.seenOptionals.has(block.id) - ) { - traverseOptionalBlock( - block as TBasicBlock, - context, - null, - ); - } - } - + traverseFunction(fn, context); return { temporariesReadInOptional: context.temporariesReadInOptional, processedInstrsInOptional: context.processedInstrsInOptional, @@ -96,8 +86,10 @@ export type OptionalChainSidemap = { * bb5: * $5 = MethodCall $2.$4() <--- here, we want to take a dep on $2 and $4! * ``` + * + * Also note that InstructionIds are not unique across inner functions. */ - processedInstrsInOptional: ReadonlySet; + processedInstrsInOptional: ReadonlySet; /** * Records optional chains for which we can safely evaluate non-optional * PropertyLoads. e.g. given `a?.b.c`, we can evaluate any load from `a?.b` at @@ -115,16 +107,46 @@ export type OptionalChainSidemap = { }; type OptionalTraversalContext = { + currFn: HIRFunction; blocks: ReadonlyMap; // Track optional blocks to avoid outer calls into nested optionals seenOptionals: Set; - processedInstrsInOptional: Set; + processedInstrsInOptional: Set; temporariesReadInOptional: Map; hoistableObjects: Map; }; +function traverseFunction( + fn: HIRFunction, + context: OptionalTraversalContext, +): void { + for (const [_, block] of fn.body.blocks) { + for (const instr of block.instructions) { + if ( + instr.value.kind === 'FunctionExpression' || + instr.value.kind === 'ObjectMethod' + ) { + traverseFunction(instr.value.loweredFunc.func, { + ...context, + currFn: instr.value.loweredFunc.func, + blocks: instr.value.loweredFunc.func.body.blocks, + }); + } + } + if ( + block.terminal.kind === 'optional' && + !context.seenOptionals.has(block.id) + ) { + traverseOptionalBlock( + block as TBasicBlock, + context, + null, + ); + } + } +} /** * Match the consequent and alternate blocks of an optional. * @returns propertyload computed by the consequent block, or null if the @@ -137,7 +159,7 @@ function matchOptionalTestBlock( consequentId: IdentifierId; property: string; propertyId: IdentifierId; - storeLocalInstrId: InstructionId; + storeLocalInstr: Instruction; consequentGoto: BlockId; } | null { const consequentBlock = assertNonNull(blocks.get(terminal.consequent)); @@ -149,7 +171,7 @@ function matchOptionalTestBlock( const propertyLoad: TInstruction = consequentBlock .instructions[0] as TInstruction; const storeLocal: StoreLocal = consequentBlock.instructions[1].value; - const storeLocalInstrId = consequentBlock.instructions[1].id; + const storeLocalInstr = consequentBlock.instructions[1]; CompilerError.invariant( propertyLoad.value.object.identifier.id === terminal.test.identifier.id, { @@ -189,7 +211,7 @@ function matchOptionalTestBlock( consequentId: storeLocal.lvalue.place.identifier.id, property: propertyLoad.value.property, propertyId: propertyLoad.lvalue.identifier.id, - storeLocalInstrId, + storeLocalInstr, consequentGoto: consequentBlock.terminal.block, }; } @@ -369,10 +391,8 @@ function traverseOptionalBlock( }, ], }; - context.processedInstrsInOptional.add( - matchConsequentResult.storeLocalInstrId, - ); - context.processedInstrsInOptional.add(test.id); + context.processedInstrsInOptional.add(matchConsequentResult.storeLocalInstr); + context.processedInstrsInOptional.add(test); context.temporariesReadInOptional.set( matchConsequentResult.consequentId, load, diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts index 0178aea6e4c56..bbec25a57cc0c 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PropagateScopeDependenciesHIR.ts @@ -16,6 +16,7 @@ import { DeclarationId, areEqualPaths, IdentifierId, + Terminal, } from './HIR'; import { collectHoistablePropertyLoads, @@ -176,8 +177,10 @@ function findTemporariesUsedOutsideDeclaringScope( * $2 = LoadLocal 'foo' * $3 = CallExpression $2($1) * ``` - * Only map LoadLocal and PropertyLoad lvalues to their source if we know that - * reordering the read (from the time-of-load to time-of-use) is valid. + * @param usedOutsideDeclaringScope is used to check the correctness of + * reordering LoadLocal / PropertyLoad calls. We only track a LoadLocal / + * PropertyLoad in the returned temporaries map if reordering the read (from the + * time-of-load to time-of-use) is valid. * * If a LoadLocal or PropertyLoad instruction is within the reactive scope range * (a proxy for mutable range) of the load source, later instructions may @@ -215,7 +218,29 @@ export function collectTemporariesSidemap( fn: HIRFunction, usedOutsideDeclaringScope: ReadonlySet, ): ReadonlyMap { - const temporaries = new Map(); + const temporaries = new Map(); + collectTemporariesSidemapImpl( + fn, + usedOutsideDeclaringScope, + temporaries, + false, + ); + return temporaries; +} + +/** + * Recursive collect a sidemap of all `LoadLocal` and `PropertyLoads` with a + * function and all nested functions. + * + * Note that IdentifierIds are currently unique, so we can use a single + * Map across all nested functions. + */ +function collectTemporariesSidemapImpl( + fn: HIRFunction, + usedOutsideDeclaringScope: ReadonlySet, + temporaries: Map, + isInnerFn: boolean, +): void { for (const [_, block] of fn.body.blocks) { for (const instr of block.instructions) { const {value, lvalue} = instr; @@ -224,27 +249,51 @@ export function collectTemporariesSidemap( ); if (value.kind === 'PropertyLoad' && !usedOutside) { - const property = getProperty( - value.object, - value.property, - false, - temporaries, - ); - temporaries.set(lvalue.identifier.id, property); + if (!isInnerFn || temporaries.has(value.object.identifier.id)) { + /** + * All dependencies of a inner / nested function must have a base + * identifier from the outermost component / hook. This is because the + * compiler cannot break an inner function into multiple granular + * scopes. + */ + const property = getProperty( + value.object, + value.property, + false, + temporaries, + ); + temporaries.set(lvalue.identifier.id, property); + } } else if ( value.kind === 'LoadLocal' && lvalue.identifier.name == null && value.place.identifier.name !== null && !usedOutside ) { - temporaries.set(lvalue.identifier.id, { - identifier: value.place.identifier, - path: [], - }); + if ( + !isInnerFn || + fn.context.some( + context => context.identifier.id === value.place.identifier.id, + ) + ) { + temporaries.set(lvalue.identifier.id, { + identifier: value.place.identifier, + path: [], + }); + } + } else if ( + value.kind === 'FunctionExpression' || + value.kind === 'ObjectMethod' + ) { + collectTemporariesSidemapImpl( + value.loweredFunc.func, + usedOutsideDeclaringScope, + temporaries, + true, + ); } } } - return temporaries; } function getProperty( @@ -310,6 +359,12 @@ class Context { #temporaries: ReadonlyMap; #temporariesUsedOutsideScope: ReadonlySet; + /** + * Tracks the traversal state. See Context.declare for explanation of why this + * is needed. + */ + inInnerFn: boolean = false; + constructor( temporariesUsedOutsideScope: ReadonlySet, temporaries: ReadonlyMap, @@ -360,12 +415,23 @@ class Context { } /* - * Records where a value was declared, and optionally, the scope where the value originated from. - * This is later used to determine if a dependency should be added to a scope; if the current - * scope we are visiting is the same scope where the value originates, it can't be a dependency - * on itself. + * Records where a value was declared, and optionally, the scope where the + * value originated from. This is later used to determine if a dependency + * should be added to a scope; if the current scope we are visiting is the + * same scope where the value originates, it can't be a dependency on itself. + * + * Note that we do not track declarations or reassignments within inner + * functions for the following reasons: + * - inner functions cannot be split by scope boundaries and are guaranteed + * to consume their own declarations + * - reassignments within inner functions are tracked as context variables, + * which already have extended mutable ranges to account for reassignments + * - *most importantly* it's currently simply incorrect to compare inner + * function instruction ids (tracked by `decl`) with outer ones (as stored + * by root identifier mutable ranges). */ declare(identifier: Identifier, decl: Decl): void { + if (this.inInnerFn) return; if (!this.#declarations.has(identifier.declarationId)) { this.#declarations.set(identifier.declarationId, decl); } @@ -575,7 +641,7 @@ function collectDependencies( fn: HIRFunction, usedOutsideDeclaringScope: ReadonlySet, temporaries: ReadonlyMap, - processedInstrsInOptional: ReadonlySet, + processedInstrsInOptional: ReadonlySet, ): Map> { const context = new Context(usedOutsideDeclaringScope, temporaries); @@ -614,12 +680,12 @@ function collectDependencies( } } for (const instr of block.instructions) { - if (!processedInstrsInOptional.has(instr.id)) { + if (!processedInstrsInOptional.has(instr)) { handleInstruction(instr, context); } } - if (!processedInstrsInOptional.has(block.terminal.id)) { + if (!processedInstrsInOptional.has(block.terminal)) { for (const place of eachTerminalOperand(block.terminal)) { context.visitOperand(place); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts index 217bc3132bd14..c9ee803bfaffd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/visitors.ts @@ -1215,9 +1215,17 @@ export class ScopeBlockTraversal { } } + /** + * @returns if the given scope is currently 'active', i.e. if the scope start + * block but not the scope fallthrough has been recorded. + */ isScopeActive(scopeId: ScopeId): boolean { return this.#activeScopes.indexOf(scopeId) !== -1; } + + /** + * The current, innermost active scope. + */ get currentScope(): ScopeId | null { return this.#activeScopes.at(-1) ?? null; } From 3dc1e4820ec985baa6668a4fa799760c4b99f5d9 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 6 Nov 2024 08:58:36 -0500 Subject: [PATCH 350/426] Followup: remove dead test code from #30346 (#31415) I missed that this was a constant false check when making the broader cleanup changes in https://github.com/facebook/react/pull/30346 --- packages/react/src/__tests__/ReactElementClone-test.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/react/src/__tests__/ReactElementClone-test.js b/packages/react/src/__tests__/ReactElementClone-test.js index 435af8e11804f..4e7d0c5ca2a2b 100644 --- a/packages/react/src/__tests__/ReactElementClone-test.js +++ b/packages/react/src/__tests__/ReactElementClone-test.js @@ -273,9 +273,6 @@ describe('ReactElementClone', () => { if (gate(flags => flags.disableStringRefs)) { expect(component.childRef).toEqual({current: null}); expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); - } else if (gate(flags => false)) { - expect(component.childRef).toEqual({current: null}); - expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); } else if (gate(flags => !flags.disableStringRefs)) { expect(component.childRef).toEqual({current: null}); expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); @@ -413,9 +410,6 @@ describe('ReactElementClone', () => { {withoutStack: true}, ); expect(clone.props).toEqual({foo: 'ef', ref: '34'}); - } else if (gate(flags => false)) { - expect(clone.ref).toBe(element.ref); - expect(clone.props).toEqual({foo: 'ef'}); } else if (gate(flags => !flags.disableStringRefs)) { expect(() => { expect(clone.ref).toBe(element.ref); From d1f04722d617600cc6cd96dcebc1c2ef7affc904 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 6 Nov 2024 09:00:49 -0500 Subject: [PATCH 351/426] [string-refs] remove enableLogStringRefsProd flag (#31414) We no longer need this production logging. --- packages/react/src/jsx/ReactJSXElement.js | 8 ++------ packages/shared/ReactFeatureFlags.js | 8 -------- packages/shared/forks/ReactFeatureFlags.native-fb.js | 1 - packages/shared/forks/ReactFeatureFlags.native-oss.js | 1 - packages/shared/forks/ReactFeatureFlags.test-renderer.js | 1 - .../shared/forks/ReactFeatureFlags.test-renderer.www.js | 1 - packages/shared/forks/ReactFeatureFlags.www-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.www.js | 1 - 8 files changed, 2 insertions(+), 20 deletions(-) diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index 1d1848e3418b8..3722638ad9515 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -23,7 +23,6 @@ import { disableStringRefs, disableDefaultPropsExceptForClasses, enableOwnerStacks, - enableLogStringRefsProd, } from 'shared/ReactFeatureFlags'; import {checkPropStringCoercion} from 'shared/CheckStringCoercion'; import {ClassComponent} from 'react-reconciler/src/ReactWorkTags'; @@ -75,7 +74,7 @@ let didWarnAboutStringRefs; let didWarnAboutElementRef; let didWarnAboutOldJSXRuntime; -if (__DEV__ || enableLogStringRefsProd) { +if (__DEV__) { didWarnAboutStringRefs = {}; didWarnAboutElementRef = {}; } @@ -1228,16 +1227,13 @@ function stringRefAsCallbackRef(stringRef, type, owner, value) { ); } - if (__DEV__ || enableLogStringRefsProd) { + if (__DEV__) { if ( // Will already warn with "Function components cannot be given refs" !(typeof type === 'function' && !isReactClass(type)) ) { const componentName = getComponentNameFromFiber(owner) || 'Component'; if (!didWarnAboutStringRefs[componentName]) { - if (enableLogStringRefsProd) { - enableLogStringRefsProd(componentName, stringRef); - } if (__DEV__) { console.error( 'Component "%s" contains the string ref "%s". Support for string refs ' + diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index a0722c31382da..d1159e60373cd 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -210,14 +210,6 @@ export const disableClientCache = true; export const disableStringRefs = true; -/** - * If set to a function, the function will be called with the component name - * and ref string. - * - * NOTE: This happens also in the production build. - */ -export const enableLogStringRefsProd: null | ((string, string) => void) = null; - // Warn on any usage of ReactTestRenderer export const enableReactTestRendererWarning = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index b4339c50a5f2f..7e63db5ef45ed 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -65,7 +65,6 @@ export const enableLazyContextPropagation = true; export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; -export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableNoCloningMemoCache = false; export const enableOwnerStacks = false; export const enablePostpone = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index ea670690a5a93..644b23b46afae 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -56,7 +56,6 @@ export const enableContextProfiling = false; export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; -export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableNoCloningMemoCache = false; export const enableObjectFiber = false; export const enableOwnerStacks = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 2eb241af6c293..2946d5efa11bc 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -44,7 +44,6 @@ export const enableUseEffectEventHook = false; export const favorSafetyOverHydrationPerf = true; export const enableComponentStackLocations = true; export const enableLegacyFBSupport = false; -export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableFilterEmptyStringAttributesDOM = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableFabricCompleteRootInCommitPhase = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 5c836b48fe2e9..5700a17f04636 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -46,7 +46,6 @@ export const enableUseEffectEventHook = false; export const favorSafetyOverHydrationPerf = true; export const enableComponentStackLocations = true; export const enableLegacyFBSupport = false; -export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableFilterEmptyStringAttributesDOM = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableRenderableContext = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index d4102efb06bcd..1c740f5211f89 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -22,7 +22,6 @@ export const disableStringRefs = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__; export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__; -export const enableLogStringRefsProd: null | ((string, string) => void) = null; export const enableNoCloningMemoCache = __VARIANT__; export const enableObjectFiber = __VARIANT__; export const enableRenderableContext = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index b86394ecf739b..c28a77626aec0 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -25,7 +25,6 @@ export const { enableDO_NOT_USE_disableStrictPassiveEffect, enableHiddenSubtreeInsertionEffectCleanup, enableInfiniteRenderLoopDetection, - enableLogStringRefsProd, enableNoCloningMemoCache, enableObjectFiber, enableRenderableContext, From 314968561b547957c76c9d7be3620e38f87770d4 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 6 Nov 2024 09:41:18 -0500 Subject: [PATCH 352/426] Back out "[bundles] stop building legacy Paper renderer (#31429)" (#31437) Backs out the 2 related commits: - https://github.com/facebook/react/commit/f8f6e1a21a1cac64cf6faf666367d641b2d8b171 - https://github.com/facebook/react/commit/6c0f37f94b020279fb5ada70facc008fccb7172e Since I only realized when syncing that we need the version of `react` and the legacy renderer to match. While I investigate if there's anything we can do to work around that while preserving the legacy renderer, this unblocks the sync. --- .../workflows/runtime_commit_artifacts.yml | 1 + scripts/rollup/bundles.js | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 37b8627be6251..7842f07ba5888 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -137,6 +137,7 @@ jobs: # Delete OSS renderer. OSS renderer is synced through internal script. RENDERER_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/implementations/ rm $RENDERER_FOLDER/ReactFabric-{dev,prod,profiling}.js + rm $RENDERER_FOLDER/ReactNativeRenderer-{dev,prod,profiling}.js # Move React Native version file mv build/facebook-react-native/VERSION_NATIVE_FB ./compiled-rn/VERSION_NATIVE_FB diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 300caae37c030..26a88fb00811d 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -696,6 +696,40 @@ const bundles = [ }), }, + /******* React Native *******/ + { + bundleTypes: __EXPERIMENTAL__ + ? [] + : [RN_FB_DEV, RN_FB_PROD, RN_FB_PROFILING], + moduleType: RENDERER, + entry: 'react-native-renderer', + global: 'ReactNativeRenderer', + externals: ['react-native', 'ReactNativeInternalFeatureFlags'], + minifyWithProdErrorCodes: false, + wrapWithModuleBoundaries: true, + babel: opts => + Object.assign({}, opts, { + plugins: opts.plugins.concat([ + [require.resolve('@babel/plugin-transform-classes'), {loose: true}], + ]), + }), + }, + { + bundleTypes: [RN_OSS_DEV, RN_OSS_PROD, RN_OSS_PROFILING], + moduleType: RENDERER, + entry: 'react-native-renderer', + global: 'ReactNativeRenderer', + externals: ['react-native'], + minifyWithProdErrorCodes: false, + wrapWithModuleBoundaries: true, + babel: opts => + Object.assign({}, opts, { + plugins: opts.plugins.concat([ + [require.resolve('@babel/plugin-transform-classes'), {loose: true}], + ]), + }), + }, + /******* React Native Fabric *******/ { bundleTypes: __EXPERIMENTAL__ From 66855b96378daedb1405e83f2365e0d90966ea0e Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Wed, 6 Nov 2024 07:35:23 -0800 Subject: [PATCH 353/426] Remove unused lastFullyObservedContext (#31435) --- .../src/ReactFiberNewContext.js | 143 ++++++++---------- 1 file changed, 66 insertions(+), 77 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberNewContext.js b/packages/react-reconciler/src/ReactFiberNewContext.js index bf28da19ce046..2e8d01e99e89c 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.js @@ -74,7 +74,6 @@ let lastContextDependency: | ContextDependency | ContextDependencyWithSelect | null = null; -let lastFullyObservedContext: ReactContext | null = null; let isDisallowedContextReadInDEV: boolean = false; @@ -83,7 +82,6 @@ export function resetContextDependencies(): void { // cannot be called outside the render phase. currentlyRenderingFiber = null; lastContextDependency = null; - lastFullyObservedContext = null; if (__DEV__) { isDisallowedContextReadInDEV = false; } @@ -730,7 +728,6 @@ export function prepareToReadContext( ): void { currentlyRenderingFiber = workInProgress; lastContextDependency = null; - lastFullyObservedContext = null; const dependencies = workInProgress.dependencies; if (dependencies !== null) { @@ -802,46 +799,42 @@ function readContextForConsumer_withSelect( ? context._currentValue : context._currentValue2; - if (lastFullyObservedContext === context) { - // Nothing to do. We already observe everything in this context. - } else { - const contextItem = { - context: ((context: any): ReactContext), - memoizedValue: value, - next: null, - select: ((select: any): (context: mixed) => Array), - lastSelectedValue: select(value), - }; - - if (lastContextDependency === null) { - if (consumer === null) { - throw new Error( - 'Context can only be read while React is rendering. ' + - 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + - 'In function components, you can read it directly in the function body, but not ' + - 'inside Hooks like useReducer() or useMemo().', - ); - } + const contextItem = { + context: ((context: any): ReactContext), + memoizedValue: value, + next: null, + select: ((select: any): (context: mixed) => Array), + lastSelectedValue: select(value), + }; + + if (lastContextDependency === null) { + if (consumer === null) { + throw new Error( + 'Context can only be read while React is rendering. ' + + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + + 'In function components, you can read it directly in the function body, but not ' + + 'inside Hooks like useReducer() or useMemo().', + ); + } - // This is the first dependency for this component. Create a new list. - lastContextDependency = contextItem; - consumer.dependencies = __DEV__ - ? { - lanes: NoLanes, - firstContext: contextItem, - _debugThenableState: null, - } - : { - lanes: NoLanes, - firstContext: contextItem, - }; - if (enableLazyContextPropagation) { - consumer.flags |= NeedsPropagation; - } - } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + consumer.dependencies = __DEV__ + ? { + lanes: NoLanes, + firstContext: contextItem, + _debugThenableState: null, + } + : { + lanes: NoLanes, + firstContext: contextItem, + }; + if (enableLazyContextPropagation) { + consumer.flags |= NeedsPropagation; } + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; } return value; } @@ -854,44 +847,40 @@ function readContextForConsumer( ? context._currentValue : context._currentValue2; - if (lastFullyObservedContext === context) { - // Nothing to do. We already observe everything in this context. - } else { - const contextItem = { - context: ((context: any): ReactContext), - memoizedValue: value, - next: null, - }; - - if (lastContextDependency === null) { - if (consumer === null) { - throw new Error( - 'Context can only be read while React is rendering. ' + - 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + - 'In function components, you can read it directly in the function body, but not ' + - 'inside Hooks like useReducer() or useMemo().', - ); - } + const contextItem = { + context: ((context: any): ReactContext), + memoizedValue: value, + next: null, + }; - // This is the first dependency for this component. Create a new list. - lastContextDependency = contextItem; - consumer.dependencies = __DEV__ - ? { - lanes: NoLanes, - firstContext: contextItem, - _debugThenableState: null, - } - : { - lanes: NoLanes, - firstContext: contextItem, - }; - if (enableLazyContextPropagation) { - consumer.flags |= NeedsPropagation; - } - } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; + if (lastContextDependency === null) { + if (consumer === null) { + throw new Error( + 'Context can only be read while React is rendering. ' + + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + + 'In function components, you can read it directly in the function body, but not ' + + 'inside Hooks like useReducer() or useMemo().', + ); + } + + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + consumer.dependencies = __DEV__ + ? { + lanes: NoLanes, + firstContext: contextItem, + _debugThenableState: null, + } + : { + lanes: NoLanes, + firstContext: contextItem, + }; + if (enableLazyContextPropagation) { + consumer.flags |= NeedsPropagation; } + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; } return value; } From a7b83e7ceb3e0390e4ad4f9b417f21cb5a0ef17f Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 6 Nov 2024 12:13:43 -0500 Subject: [PATCH 354/426] [www] set disableStringRefs to true (#31438) --- packages/shared/forks/ReactFeatureFlags.test-renderer.www.js | 2 +- packages/shared/forks/ReactFeatureFlags.www-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.www.js | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 5700a17f04636..8e9e8f0ca2d58 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -82,7 +82,7 @@ export const disableClientCache = true; export const enableServerComponentLogs = true; export const enableInfiniteRenderLoopDetection = false; -export const disableStringRefs = false; +export const disableStringRefs = true; export const enableReactTestRendererWarning = false; export const disableLegacyMode = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 1c740f5211f89..8a82b7f55241b 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -18,7 +18,6 @@ export const disableDefaultPropsExceptForClasses = __VARIANT__; export const disableLegacyContextForFunctionComponents = __VARIANT__; export const disableLegacyMode = __VARIANT__; export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; -export const disableStringRefs = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__; export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index c28a77626aec0..dac110129ef53 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -19,7 +19,6 @@ export const { disableDefaultPropsExceptForClasses, disableLegacyContextForFunctionComponents, disableSchedulerTimeoutInWorkLoop, - disableStringRefs, enableDebugTracing, enableDeferRootSchedulingToMicrotask, enableDO_NOT_USE_disableStrictPassiveEffect, @@ -53,6 +52,7 @@ export const enableSuspenseAvoidThisFallback = true; export const enableSuspenseAvoidThisFallbackFizz = false; export const disableIEWorkarounds = true; +export const disableStringRefs = true; export const enableCPUSuspense = true; export const enableUseMemoCacheHook = true; export const enableUseEffectEventHook = true; From 2df8f6188537514a538741064ae83682c2bef7c1 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Wed, 6 Nov 2024 17:44:52 +0000 Subject: [PATCH 355/426] [compiler] Store original and new prop names (#31440) Previously, we'd directly store the original attributes from the jsx expressions. But this isn't enough as we want to rename duplicate attributes. This PR refactors the prop collection logic to store both the original and new names for jsx attributes in the newly outlined jsx expression. For now, both the new and old names are the same. In the future, they will be different when we add support for outlining expressions with duplicate attribute names. --- .../src/Optimization/OutlineJsx.ts | 76 ++++++++++++------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts index f10f97c425dd0..6efcc16538e06 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts @@ -210,10 +210,16 @@ function process( return {instrs: newInstrs, fn: outlinedFn}; } +type OutlinedJsxAttribute = { + originalName: string; + newName: string; + place: Place; +}; + function collectProps( instructions: Array, -): Array | null { - const attributes: Array = []; +): Array | null { + const attributes: Array = []; const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id)); const seen: Set = new Set(); for (const instr of instructions) { @@ -234,7 +240,11 @@ function collectProps( if (at.kind === 'JsxAttribute') { seen.add(at.name); - attributes.push(at); + attributes.push({ + originalName: at.name, + newName: at.name, + place: at.place, + }); } } @@ -252,9 +262,15 @@ function collectProps( function emitOutlinedJsx( env: Environment, instructions: Array, - props: Array, + outlinedProps: Array, outlinedTag: string, ): Array { + const props: Array = outlinedProps.map(p => ({ + kind: 'JsxAttribute', + name: p.newName, + place: p.place, + })); + const loadJsx: Instruction = { id: makeInstructionId(0), loc: GeneratedSource, @@ -290,7 +306,7 @@ function emitOutlinedJsx( function emitOutlinedFn( env: Environment, jsx: Array, - oldProps: Array, + oldProps: Array, globals: LoadGlobalMap, ): HIRFunction | null { const instructions: Array = []; @@ -299,9 +315,11 @@ function emitOutlinedFn( const propsObj: Place = createTemporaryPlace(env, GeneratedSource); promoteTemporary(propsObj.identifier); - const destructurePropsInstr = emitDestructureProps(env, propsObj, [ - ...oldToNewProps.values(), - ]); + const destructurePropsInstr = emitDestructureProps( + env, + propsObj, + oldToNewProps, + ); instructions.push(destructurePropsInstr); const updatedJsxInstructions = emitUpdatedJsx(jsx, oldToNewProps); @@ -368,7 +386,7 @@ function emitLoadGlobals( function emitUpdatedJsx( jsx: Array, - oldToNewProps: Map, + oldToNewProps: Map, ): Array { const newInstrs: Array = []; @@ -390,7 +408,8 @@ function emitUpdatedJsx( `Expected a new property for ${printIdentifier(prop.place.identifier)}`, ); newProps.push({ - ...prop, + kind: 'JsxAttribute', + name: newProp.originalName, place: newProp.place, }); } @@ -409,31 +428,21 @@ function emitUpdatedJsx( function createOldToNewPropsMapping( env: Environment, - oldProps: Array, -): Map { + oldProps: Array, +): Map { const oldToNewProps = new Map(); for (const oldProp of oldProps) { - invariant( - oldProp.kind === 'JsxAttribute', - `Expected only attributes but found ${oldProp.kind}`, - ); - // Do not read key prop in the outlined component - if (oldProp.name === 'key') { + if (oldProp.originalName === 'key') { continue; } - const newProp: ObjectProperty = { - kind: 'ObjectProperty', - key: { - kind: 'string', - name: oldProp.name, - }, - type: 'property', + const newProp: OutlinedJsxAttribute = { + ...oldProp, place: createTemporaryPlace(env, GeneratedSource), }; - newProp.place.identifier.name = makeIdentifierName(oldProp.name); + newProp.place.identifier.name = makeIdentifierName(oldProp.newName); oldToNewProps.set(oldProp.place.identifier.id, newProp); } @@ -443,8 +452,21 @@ function createOldToNewPropsMapping( function emitDestructureProps( env: Environment, propsObj: Place, - properties: Array, + oldToNewProps: Map, ): Instruction { + const properties: Array = []; + for (const [_, prop] of oldToNewProps) { + properties.push({ + kind: 'ObjectProperty', + key: { + kind: 'string', + name: prop.newName, + }, + type: 'property', + place: prop.place, + }); + } + const destructurePropsInstr: Instruction = { id: makeInstructionId(0), lvalue: createTemporaryPlace(env, GeneratedSource), From 09197bb786344d2ede1286e7f3ec4e21b18a58f2 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Wed, 6 Nov 2024 17:50:13 +0000 Subject: [PATCH 356/426] [compiler] Outline jsx with duplicate attributes (#31441) Previously, we would skip outlining jsx expressions that had duplicate jsx attributes as we would not rename them causing incorrect compilation. In this PR, we add outlining support for duplicate jsx attributes by renaming them. --- .../src/Optimization/OutlineJsx.ts | 18 +- ...jsx-outlining-dup-key-diff-value.expect.md | 166 ++++++++++++++++ .../jsx-outlining-dup-key-diff-value.js | 41 ++++ ...outlining-dupe-attr-after-rename.expect.md | 177 ++++++++++++++++++ .../jsx-outlining-dupe-attr-after-rename.js | 42 +++++ ...utlining-dupe-key-dupe-component.expect.md | 157 ++++++++++++++++ .../jsx-outlining-dupe-key-dupe-component.js | 37 ++++ ...=> jsx-outlining-duplicate-prop.expect.md} | 56 ++++-- ...rop.js => jsx-outlining-duplicate-prop.js} | 4 +- 9 files changed, 675 insertions(+), 23 deletions(-) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.js rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{todo.jsx-outlining-duplicate-prop.expect.md => jsx-outlining-duplicate-prop.expect.md} (68%) rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{todo.jsx-outlining-duplicate-prop.js => jsx-outlining-duplicate-prop.js} (94%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts index 6efcc16538e06..b5e92171c15ca 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts @@ -222,6 +222,8 @@ function collectProps( const attributes: Array = []; const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id)); const seen: Set = new Set(); + let id = 1; + for (const instr of instructions) { const {value} = instr; @@ -230,21 +232,17 @@ function collectProps( return null; } - /* - * TODO(gsn): Handle attributes that have same value across - * the outlined jsx instructions. - */ - if (seen.has(at.name)) { - return null; - } - if (at.kind === 'JsxAttribute') { - seen.add(at.name); + let newName = at.name; + while (seen.has(newName)) { + newName = `${at.name}${id++}`; + } attributes.push({ originalName: at.name, - newName: at.name, + newName, place: at.place, }); + seen.add(newName); } } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.expect.md new file mode 100644 index 0000000000000..ded6e67020fa7 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.expect.md @@ -0,0 +1,166 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== arr || $[1] !== x) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => { + const T0 = _temp; + return ; + }; + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = arr; + $[1] = x; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +function _temp(t0) { + const $ = _c(8); + const { i: i, k: k, x: x } = t0; + let t1; + if ($[0] !== i) { + t1 = ; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== k) { + t2 = ; + $[2] = k; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== t1 || $[5] !== t2 || $[6] !== x) { + t3 = ( + + {t1} + {t2} + + ); + $[4] = t1; + $[5] = t2; + $[6] = x; + $[7] = t3; + } else { + t3 = $[7]; + } + return t3; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== children || $[1] !== x) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = children; + $[1] = x; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { i } = t0; + return i; +} + +function Foo(t0) { + const { k } = t0; + return k; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooifoojxbaribarj \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.js new file mode 100644 index 0000000000000..63086739a230b --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dup-key-diff-value.js @@ -0,0 +1,41 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({i}) { + return i; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.expect.md new file mode 100644 index 0000000000000..c95e23222ed72 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.expect.md @@ -0,0 +1,177 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({k1}) { + return k1; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== arr || $[1] !== x) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => { + const T0 = _temp; + return ; + }; + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = arr; + $[1] = x; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +function _temp(t0) { + const $ = _c(11); + const { k: k, k1: k1, k12: k12, x: x } = t0; + let t1; + if ($[0] !== k) { + t1 = ; + $[0] = k; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== k1) { + t2 = ; + $[2] = k1; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== k12) { + t3 = ; + $[4] = k12; + $[5] = t3; + } else { + t3 = $[5]; + } + let t4; + if ($[6] !== t1 || $[7] !== t2 || $[8] !== t3 || $[9] !== x) { + t4 = ( + + {t1} + {t2} + {t3} + + ); + $[6] = t1; + $[7] = t2; + $[8] = t3; + $[9] = x; + $[10] = t4; + } else { + t4 = $[10]; + } + return t4; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== children || $[1] !== x) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = children; + $[1] = x; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Baz(t0) { + const { k1 } = t0; + return k1; +} + +function Foo(t0) { + const { k } = t0; + return k; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooifoojfoojxbaribarjbarj \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.js new file mode 100644 index 0000000000000..09a826492a556 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-attr-after-rename.js @@ -0,0 +1,42 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Baz({k1}) { + return k1; +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.expect.md new file mode 100644 index 0000000000000..a53d9d92aa672 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.expect.md @@ -0,0 +1,157 @@ + +## Input + +```javascript +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining +function Component(t0) { + const $ = _c(7); + const { arr } = t0; + const x = useX(); + let t1; + if ($[0] !== arr || $[1] !== x) { + let t2; + if ($[3] !== x) { + t2 = (i, id) => { + const T0 = _temp; + return ; + }; + $[3] = x; + $[4] = t2; + } else { + t2 = $[4]; + } + t1 = arr.map(t2); + $[0] = arr; + $[1] = x; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[5] !== t1) { + t2 = <>{t1}; + $[5] = t1; + $[6] = t2; + } else { + t2 = $[6]; + } + return t2; +} +function _temp(t0) { + const $ = _c(8); + const { k: k, k1: k1, x: x } = t0; + let t1; + if ($[0] !== k) { + t1 = ; + $[0] = k; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== k1) { + t2 = ; + $[2] = k1; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== t1 || $[5] !== t2 || $[6] !== x) { + t3 = ( + + {t1} + {t2} + + ); + $[4] = t1; + $[5] = t2; + $[6] = x; + $[7] = t3; + } else { + t3 = $[7]; + } + return t3; +} + +function Bar(t0) { + const $ = _c(3); + const { x, children } = t0; + let t1; + if ($[0] !== children || $[1] !== x) { + t1 = ( + <> + {x} + {children} + + ); + $[0] = children; + $[1] = x; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Foo(t0) { + const { k } = t0; + return k; +} + +function useX() { + return "x"; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ arr: ["foo", "bar"] }], +}; + +``` + +### Eval output +(kind: ok) xfooifoojxbaribarj \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.js new file mode 100644 index 0000000000000..aa7cb548ce911 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-dupe-key-dupe-component.js @@ -0,0 +1,37 @@ +// @enableJsxOutlining +function Component({arr}) { + const x = useX(); + return ( + <> + {arr.map((i, id) => { + return ( + + + + + ); + })} + + ); +} +function Bar({x, children}) { + return ( + <> + {x} + {children} + + ); +} + +function Foo({k}) { + return k; +} + +function useX() { + return 'x'; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{arr: ['foo', 'bar']}], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-duplicate-prop.expect.md similarity index 68% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-duplicate-prop.expect.md index c661094fdd455..e6ba7dd7ee7c7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-duplicate-prop.expect.md @@ -31,8 +31,8 @@ function Baz({i}) { return i; } -function Foo({k}) { - return k; +function Foo({i}) { + return i; } function useX() { @@ -58,12 +58,10 @@ function Component(t0) { if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { - t2 = (i, id) => ( - - - - - ); + t2 = (i, id) => { + const T0 = _temp; + return ; + }; $[3] = x; $[4] = t2; } else { @@ -86,6 +84,42 @@ function Component(t0) { } return t2; } +function _temp(t0) { + const $ = _c(8); + const { i: i, i1: i1, x: x } = t0; + let t1; + if ($[0] !== i) { + t1 = ; + $[0] = i; + $[1] = t1; + } else { + t1 = $[1]; + } + let t2; + if ($[2] !== i1) { + t2 = ; + $[2] = i1; + $[3] = t2; + } else { + t2 = $[3]; + } + let t3; + if ($[4] !== t1 || $[5] !== t2 || $[6] !== x) { + t3 = ( + + {t1} + {t2} + + ); + $[4] = t1; + $[5] = t2; + $[6] = x; + $[7] = t3; + } else { + t3 = $[7]; + } + return t3; +} function Bar(t0) { const $ = _c(3); @@ -113,8 +147,8 @@ function Baz(t0) { } function Foo(t0) { - const { k } = t0; - return k; + const { i } = t0; + return i; } function useX() { @@ -129,4 +163,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: ok) xfooxbar \ No newline at end of file +(kind: ok) xfoofooxbarbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-duplicate-prop.js similarity index 94% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-duplicate-prop.js index 20c6bd934a5d0..0314ce8c67651 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-duplicate-prop.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-duplicate-prop.js @@ -27,8 +27,8 @@ function Baz({i}) { return i; } -function Foo({k}) { - return k; +function Foo({i}) { + return i; } function useX() { From a88b9e5f6882a121417b2e8434d4c7ec30a60c52 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Wed, 6 Nov 2024 17:54:44 +0000 Subject: [PATCH 357/426] [compiler] Outline JSX with non-jsx children (#31442) Previously, we bailed out on outlining jsx that had children that were not part of the outlined jsx. Now, we add support for children by treating as attributes. --- .../src/Optimization/OutlineJsx.ts | 58 +++++++++--- ...outlining-with-non-jsx-children.expect.md} | 88 ++++++++++++++++--- ...=> jsx-outlining-with-non-jsx-children.js} | 15 +++- 3 files changed, 137 insertions(+), 24 deletions(-) rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{todo.jsx-outlining-children.expect.md => jsx-outlining-with-non-jsx-children.expect.md} (55%) rename compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/{todo.jsx-outlining-children.js => jsx-outlining-with-non-jsx-children.js} (75%) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts index b5e92171c15ca..a6b94075cce26 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts @@ -219,10 +219,20 @@ type OutlinedJsxAttribute = { function collectProps( instructions: Array, ): Array | null { + let id = 1; + + function generateName(oldName: string): string { + let newName = oldName; + while (seen.has(newName)) { + newName = `${oldName}${id++}`; + } + seen.add(newName); + return newName; + } + const attributes: Array = []; const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id)); const seen: Set = new Set(); - let id = 1; for (const instr of instructions) { const {value} = instr; @@ -233,25 +243,29 @@ function collectProps( } if (at.kind === 'JsxAttribute') { - let newName = at.name; - while (seen.has(newName)) { - newName = `${at.name}${id++}`; - } + const newName = generateName(at.name); attributes.push({ originalName: at.name, newName, place: at.place, }); - seen.add(newName); } } - // TODO(gsn): Add support for children that are not jsx expressions - if ( - value.children && - value.children.some(child => !jsxIds.has(child.identifier.id)) - ) { - return null; + if (value.children) { + for (const child of value.children) { + if (jsxIds.has(child.identifier.id)) { + continue; + } + + promoteTemporary(child.identifier); + const newName = generateName('t'); + attributes.push({ + originalName: child.identifier.name!.value, + newName: newName, + place: child, + }); + } } } return attributes; @@ -387,6 +401,7 @@ function emitUpdatedJsx( oldToNewProps: Map, ): Array { const newInstrs: Array = []; + const jsxIds = new Set(jsx.map(i => i.lvalue.identifier.id)); for (const instr of jsx) { const {value} = instr; @@ -412,11 +427,30 @@ function emitUpdatedJsx( }); } + let newChildren: Array | null = null; + if (value.children) { + newChildren = []; + for (const child of value.children) { + if (jsxIds.has(child.identifier.id)) { + newChildren.push({...child}); + continue; + } + + const newChild = oldToNewProps.get(child.identifier.id); + invariant( + newChild !== undefined, + `Expected a new prop for ${printIdentifier(child.identifier)}`, + ); + newChildren.push({...newChild.place}); + } + } + newInstrs.push({ ...instr, value: { ...value, props: newProps, + children: newChildren, }, }); } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-with-non-jsx-children.expect.md similarity index 55% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-with-non-jsx-children.expect.md index 4864c51a1fe25..5408ea83a831b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-with-non-jsx-children.expect.md @@ -11,12 +11,14 @@ function Component({arr}) { return ( Test + ); })} ); } + function Bar({x, children}) { return ( <> @@ -26,8 +28,17 @@ function Bar({x, children}) { ); } -function Baz({i}) { - return i; +function Baz({i, children}) { + return ( + <> + {i} + {children} + + ); +} + +function Foo({k}) { + return k; } function useX() { @@ -53,11 +64,11 @@ function Component(t0) { if ($[0] !== arr || $[1] !== x) { let t2; if ($[3] !== x) { - t2 = (i, id) => ( - - Test - - ); + t2 = (i, id) => { + const t3 = "Test"; + const T0 = _temp; + return ; + }; $[3] = x; $[4] = t2; } else { @@ -80,6 +91,43 @@ function Component(t0) { } return t2; } +function _temp(t0) { + const $ = _c(9); + const { i: i, t: t, k: k, x: x } = t0; + let t1; + if ($[0] !== i || $[1] !== t) { + t1 = {t}; + $[0] = i; + $[1] = t; + $[2] = t1; + } else { + t1 = $[2]; + } + let t2; + if ($[3] !== k) { + t2 = ; + $[3] = k; + $[4] = t2; + } else { + t2 = $[4]; + } + let t3; + if ($[5] !== t1 || $[6] !== t2 || $[7] !== x) { + t3 = ( + + {t1} + {t2} + + ); + $[5] = t1; + $[6] = t2; + $[7] = x; + $[8] = t3; + } else { + t3 = $[8]; + } + return t3; +} function Bar(t0) { const $ = _c(3); @@ -102,8 +150,28 @@ function Bar(t0) { } function Baz(t0) { - const { i } = t0; - return i; + const $ = _c(3); + const { i, children } = t0; + let t1; + if ($[0] !== children || $[1] !== i) { + t1 = ( + <> + {i} + {children} + + ); + $[0] = children; + $[1] = i; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +function Foo(t0) { + const { k } = t0; + return k; } function useX() { @@ -118,4 +186,4 @@ export const FIXTURE_ENTRYPOINT = { ``` ### Eval output -(kind: ok) xfooxbar \ No newline at end of file +(kind: ok) xfooTestfooxbarTestbar \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-with-non-jsx-children.js similarity index 75% rename from compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js rename to compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-with-non-jsx-children.js index eab907e09e21d..552db93e8373e 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/todo.jsx-outlining-children.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/jsx-outlining-with-non-jsx-children.js @@ -7,12 +7,14 @@ function Component({arr}) { return ( Test + ); })} ); } + function Bar({x, children}) { return ( <> @@ -22,8 +24,17 @@ function Bar({x, children}) { ); } -function Baz({i}) { - return i; +function Baz({i, children}) { + return ( + <> + {i} + {children} + + ); +} + +function Foo({k}) { + return k; } function useX() { From e1378902bbb322aa1fe1953780f4b2b5f80d26b1 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 6 Nov 2024 14:00:10 -0500 Subject: [PATCH 358/426] [string-refs] cleanup string ref code (#31443) --- packages/jest-react/src/JestReact.js | 11 - .../react-client/src/ReactFlightClient.js | 14 - .../src/__tests__/ReactFlight-test.js | 4 +- .../src/__tests__/ReactComponent-test.js | 112 ------- .../__tests__/ReactCompositeComponent-test.js | 7 +- .../ReactDOMServerIntegrationRefs-test.js | 38 +-- .../ReactDeprecationWarnings-test.js | 117 ------- .../__tests__/ReactFunctionComponent-test.js | 18 -- .../multiple-copies-of-react-test.js | 38 --- packages/react-dom/src/__tests__/refs-test.js | 301 ------------------ .../src/createReactNoop.js | 12 +- .../src/ReactFiberAsyncDispatcher.js | 4 +- .../src/ReactFiberBeginWork.js | 22 +- .../src/ReactFiberCommitEffects.js | 3 +- .../src/ReactFiberWorkLoop.js | 15 +- .../src/ReactInternalTypes.js | 2 +- .../src/__tests__/ReactFiberRefs-test.js | 29 -- .../ReactIncrementalSideEffects-test.js | 34 -- .../src/__tests__/ReactFlightDOMEdge-test.js | 4 +- .../src/ReactFizzAsyncDispatcher.js | 6 - packages/react-server/src/ReactFizzServer.js | 3 +- .../src/flight/ReactFlightAsyncDispatcher.js | 10 - .../ReactCoffeeScriptClass-test.coffee | 21 -- .../src/__tests__/ReactCreateElement-test.js | 2 +- .../react/src/__tests__/ReactES6Class-test.js | 21 -- .../src/__tests__/ReactElementClone-test.js | 68 +--- .../src/__tests__/ReactStrictMode-test.js | 49 --- .../__tests__/ReactTypeScriptClass-test.ts | 16 - packages/react/src/jsx/ReactJSXElement.js | 205 +----------- packages/shared/ReactFeatureFlags.js | 2 - .../forks/ReactFeatureFlags.native-fb.js | 1 - .../forks/ReactFeatureFlags.native-oss.js | 1 - .../forks/ReactFeatureFlags.test-renderer.js | 1 - ...actFeatureFlags.test-renderer.native-fb.js | 1 - .../ReactFeatureFlags.test-renderer.www.js | 2 - .../shared/forks/ReactFeatureFlags.www.js | 1 - 36 files changed, 35 insertions(+), 1160 deletions(-) delete mode 100644 packages/react-dom/src/__tests__/multiple-copies-of-react-test.js diff --git a/packages/jest-react/src/JestReact.js b/packages/jest-react/src/JestReact.js index 8fcec97f63f7a..3cb9ab88f32f1 100644 --- a/packages/jest-react/src/JestReact.js +++ b/packages/jest-react/src/JestReact.js @@ -6,7 +6,6 @@ */ import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols'; -import {disableStringRefs} from 'shared/ReactFeatureFlags'; const {assertConsoleLogsCleared} = require('internal-test-utils/consoleMock'); import isArray from 'shared/isArray'; @@ -56,14 +55,6 @@ function createJSXElementForTestComparison(type, props) { value: null, }); return element; - } else if (!__DEV__ && disableStringRefs) { - return { - $$typeof: REACT_ELEMENT_TYPE, - type: type, - key: null, - ref: null, - props: props, - }; } else { return { $$typeof: REACT_ELEMENT_TYPE, @@ -71,8 +62,6 @@ function createJSXElementForTestComparison(type, props) { key: null, ref: null, props: props, - _owner: null, - _store: __DEV__ ? {} : undefined, }; } } diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js index 6c370bd2ef652..9a3d3e0198671 100644 --- a/packages/react-client/src/ReactFlightClient.js +++ b/packages/react-client/src/ReactFlightClient.js @@ -41,7 +41,6 @@ import type {Postpone} from 'react/src/ReactPostpone'; import type {TemporaryReferenceSet} from './ReactFlightTemporaryReferences'; import { - disableStringRefs, enableBinaryFlight, enablePostpone, enableFlightReadableStream, @@ -688,16 +687,6 @@ function createElement( enumerable: false, get: nullRefGetter, }); - } else if (!__DEV__ && disableStringRefs) { - element = ({ - // This tag allows us to uniquely identify this as a React Element - $$typeof: REACT_ELEMENT_TYPE, - - type, - key, - ref: null, - props, - }: any); } else { element = ({ // This tag allows us to uniquely identify this as a React Element @@ -707,9 +696,6 @@ function createElement( key, ref: null, props, - - // Record the component responsible for creating this element. - _owner: __DEV__ && owner === null ? response._debugRootOwner : owner, }: any); } diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 47c6db808f043..dc33d03f94261 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -3268,9 +3268,7 @@ describe('ReactFlight', () => { expect(greeting._owner).toBe(greeting._debugInfo[0]); } else { expect(greeting._debugInfo).toBe(undefined); - expect(greeting._owner).toBe( - gate(flags => flags.disableStringRefs) ? undefined : null, - ); + expect(greeting._owner).toBe(undefined); } ReactNoop.render(greeting); }); diff --git a/packages/react-dom/src/__tests__/ReactComponent-test.js b/packages/react-dom/src/__tests__/ReactComponent-test.js index 9b2f443a7c34d..6459114697540 100644 --- a/packages/react-dom/src/__tests__/ReactComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactComponent-test.js @@ -42,19 +42,6 @@ describe('ReactComponent', () => { }).toThrowError(/Target container is not a DOM element./); }); - // @gate !disableStringRefs - it('should throw when supplying a string ref outside of render method', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect( - act(() => { - root.render(
); - }), - // TODO: This throws an AggregateError. Need to update test infra to - // support matching against AggregateError. - ).rejects.toThrow(); - }); - it('should throw (in dev) when children are mutated during render', async () => { function Wrapper(props) { props.children[1] =

; // Mutation is illegal @@ -132,105 +119,6 @@ describe('ReactComponent', () => { } }); - // @gate !disableStringRefs - it('string refs do not detach and reattach on every render', async () => { - let refVal; - class Child extends React.Component { - componentDidUpdate() { - // The parent ref should still be attached because it hasn't changed - // since the last render. If the ref had changed, then this would be - // undefined because refs are attached during the same phase (layout) - // as componentDidUpdate, in child -> parent order. So the new parent - // ref wouldn't have attached yet. - refVal = this.props.contextRef(); - } - - render() { - if (this.props.show) { - return

child
; - } - } - } - - class Parent extends React.Component { - render() { - return ( -
- this.refs.root} - show={this.props.showChild} - /> -
- ); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - - await act(() => { - root.render(); - }); - - assertConsoleErrorDev(['contains the string ref']); - - expect(refVal).toBe(undefined); - await act(() => { - root.render(); - }); - expect(refVal).toBe(container.querySelector('#test-root')); - }); - - // @gate !disableStringRefs - it('should support string refs on owned components', async () => { - const innerObj = {}; - const outerObj = {}; - - class Wrapper extends React.Component { - getObject = () => { - return this.props.object; - }; - - render() { - return
{this.props.children}
; - } - } - - class Component extends React.Component { - render() { - const inner = ; - const outer = ( - - {inner} - - ); - return outer; - } - - componentDidMount() { - expect(this.refs.inner.getObject()).toEqual(innerObj); - expect(this.refs.outer.getObject()).toEqual(outerObj); - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev([ - 'Component "Component" contains the string ref "inner". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in Wrapper (at **)\n' + - ' in div (at **)\n' + - ' in Wrapper (at **)\n' + - ' in Component (at **)', - ]); - }); - it('should not have string refs on unmounted components', async () => { class Parent extends React.Component { render() { diff --git a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js index 89d0b83abc3b1..4444076681208 100644 --- a/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactCompositeComponent-test.js @@ -537,11 +537,8 @@ describe('ReactCompositeComponent', () => { }); it('should cleanup even if render() fatals', async () => { - const dispatcherEnabled = - __DEV__ || - !gate(flags => flags.disableStringRefs) || - gate(flags => flags.enableCache); - const ownerEnabled = __DEV__ || !gate(flags => flags.disableStringRefs); + const dispatcherEnabled = __DEV__ || gate(flags => flags.enableCache); + const ownerEnabled = __DEV__; let stashedDispatcher; class BadComponent extends React.Component { diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js index b8d1a0716ae52..9094af348472f 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js @@ -29,12 +29,8 @@ function initModules() { }; } -const { - resetModules, - asyncReactDOMRender, - clientRenderOnServerString, - expectMarkupMatch, -} = ReactDOMServerIntegrationUtils(initModules); +const {resetModules, clientRenderOnServerString, expectMarkupMatch} = + ReactDOMServerIntegrationUtils(initModules); describe('ReactDOMServerIntegration', () => { beforeEach(() => { @@ -75,36 +71,6 @@ describe('ReactDOMServerIntegration', () => { expect(refElement).not.toBe(null); expect(refElement).toBe(e); }); - - // @gate !disableStringRefs - it('should have string refs on client when rendered over server markup', async () => { - class RefsComponent extends React.Component { - render() { - return
; - } - } - - const markup = ReactDOMServer.renderToString(); - const root = document.createElement('div'); - root.innerHTML = markup; - let component = null; - resetModules(); - await expect(async () => { - await asyncReactDOMRender( - (component = e)} />, - root, - true, - ); - }).toErrorDev([ - 'Component "RefsComponent" contains the string ref "myDiv". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in div (at **)\n' + - ' in RefsComponent (at **)', - ]); - expect(component.refs.myDiv).toBe(root.firstChild); - }); }); it('should forward refs', async () => { diff --git a/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js b/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js index 77c9e1886e0a8..e0022dd99004b 100644 --- a/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js +++ b/packages/react-dom/src/__tests__/ReactDeprecationWarnings-test.js @@ -11,7 +11,6 @@ let React; let ReactNoop; -let JSXDEVRuntime; let waitForAll; describe('ReactDeprecationWarnings', () => { @@ -21,9 +20,6 @@ describe('ReactDeprecationWarnings', () => { ReactNoop = require('react-noop-renderer'); const InternalTestUtils = require('internal-test-utils'); waitForAll = InternalTestUtils.waitForAll; - if (__DEV__) { - JSXDEVRuntime = require('react/jsx-dev-runtime'); - } }); // @gate !disableDefaultPropsExceptForClasses || !__DEV__ @@ -65,117 +61,4 @@ describe('ReactDeprecationWarnings', () => { 'release. Use JavaScript default parameters instead.', ); }); - - // @gate !disableStringRefs - it('should warn when given string refs', async () => { - class RefComponent extends React.Component { - render() { - return null; - } - } - class Component extends React.Component { - render() { - return ; - } - } - - ReactNoop.render(); - await expect(async () => await waitForAll([])).toErrorDev( - 'Component "Component" contains the string ref "refComponent". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref' + - '\n in RefComponent (at **)' + - '\n in Component (at **)', - ); - }); - - // Disabling this until #28732 lands so we can assert on the warning message. - // (It's already disabled in all but the Meta builds, anyway. Nbd.) - // @gate TODO || !__DEV__ - // @gate !disableStringRefs - it('should warn when owner and self are the same for string refs', async () => { - class RefComponent extends React.Component { - render() { - return null; - } - } - class Component extends React.Component { - render() { - return React.createElement(RefComponent, { - ref: 'refComponent', - __self: this, - }); - } - } - - ReactNoop.render(); - await expect(async () => await waitForAll([])).toErrorDev([ - 'Component "Component" contains the string ref "refComponent". Support for string refs will be removed in a future major release.', - ]); - await waitForAll([]); - }); - - // Disabling this until #28732 lands so we can assert on the warning message. - // (It's already disabled in all but the Meta builds, anyway. Nbd.) - // @gate TODO || !__DEV__ - // @gate !disableStringRefs - it('should warn when owner and self are different for string refs (createElement)', async () => { - class RefComponent extends React.Component { - render() { - return null; - } - } - class Component extends React.Component { - render() { - return React.createElement(RefComponent, { - ref: 'refComponent', - __self: {}, - }); - } - } - - ReactNoop.render(); - await expect(async () => await waitForAll([])).toErrorDev([ - 'Component "Component" contains the string ref "refComponent". ' + - 'Support for string refs will be removed in a future major release. ' + - 'This case cannot be automatically converted to an arrow function. ' + - 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref', - ]); - }); - - // @gate __DEV__ - // @gate !disableStringRefs - it('should warn when owner and self are different for string refs (jsx)', async () => { - class RefComponent extends React.Component { - render() { - return null; - } - } - class Component extends React.Component { - render() { - return JSXDEVRuntime.jsxDEV( - RefComponent, - {ref: 'refComponent'}, - null, - false, - {}, - {}, - ); - } - } - - ReactNoop.render(); - await expect(async () => await waitForAll([])).toErrorDev([ - 'Component "Component" contains the string ref "refComponent". ' + - 'Support for string refs will be removed in a future major release. ' + - 'This case cannot be automatically converted to an arrow function. ' + - 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref', - ]); - }); }); diff --git a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js index 24f97520ecc3d..f1250ce26d7c9 100644 --- a/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactFunctionComponent-test.js @@ -179,24 +179,6 @@ describe('ReactFunctionComponent', () => { ).resolves.not.toThrowError(); }); - // @gate !disableStringRefs - it('should throw on string refs in pure functions', async () => { - function Child() { - return
; - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect( - act(() => { - root.render(); - }), - ) - // TODO: This throws an AggregateError. Need to update test infra to - // support matching against AggregateError. - .rejects.toThrowError(); - }); - it('should use correct name in key warning', async () => { function Child() { return
{[]}
; diff --git a/packages/react-dom/src/__tests__/multiple-copies-of-react-test.js b/packages/react-dom/src/__tests__/multiple-copies-of-react-test.js deleted file mode 100644 index 2d107cbb19700..0000000000000 --- a/packages/react-dom/src/__tests__/multiple-copies-of-react-test.js +++ /dev/null @@ -1,38 +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. - * - * @emails react-core - */ - -'use strict'; - -let React = require('react'); -const ReactDOMClient = require('react-dom/client'); -const act = require('internal-test-utils').act; - -class TextWithStringRef extends React.Component { - render() { - jest.resetModules(); - React = require('react'); - return Hello world!; - } -} - -describe('when different React version is used with string ref', () => { - // @gate !disableStringRefs - it('throws the "Refs must have owner" warning', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect( - act(() => { - root.render(); - }), - ) - // TODO: This throws an AggregateError. Need to update test infra to - // support matching against AggregateError. - .rejects.toThrow(); - }); -}); diff --git a/packages/react-dom/src/__tests__/refs-test.js b/packages/react-dom/src/__tests__/refs-test.js index 80ea8d1e26b32..b80f8b27753f2 100644 --- a/packages/react-dom/src/__tests__/refs-test.js +++ b/packages/react-dom/src/__tests__/refs-test.js @@ -13,179 +13,6 @@ const React = require('react'); const ReactDOMClient = require('react-dom/client'); const act = require('internal-test-utils').act; -// This is testing if string refs are deleted from `instance.refs` -// Once support for string refs is removed, this test can be removed. -// Detaching is already tested in refs-detruction-test.js -describe('reactiverefs', () => { - let container; - - afterEach(() => { - if (container) { - document.body.removeChild(container); - container = null; - } - }); - - /** - * Counts clicks and has a renders an item for each click. Each item rendered - * has a ref of the form "clickLogN". - */ - class ClickCounter extends React.Component { - state = {count: this.props.initialCount}; - - triggerReset = () => { - this.setState({count: this.props.initialCount}); - }; - - handleClick = () => { - this.setState({count: this.state.count + 1}); - }; - - render() { - const children = []; - let i; - for (i = 0; i < this.state.count; i++) { - children.push( -
, - ); - } - return ( - - {children} - - ); - } - } - - const expectClickLogsLengthToBe = function (instance, length) { - const clickLogs = instance.container.querySelectorAll('.clickLogDiv'); - expect(clickLogs.length).toBe(length); - expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length); - }; - - /** - * Render a TestRefsComponent and ensure that the main refs are wired up. - */ - const renderTestRefsComponent = async function () { - /** - * Only purpose is to test that refs are tracked even when applied to a - * component that is injected down several layers. Ref systems are difficult to - * build in such a way that ownership is maintained in an airtight manner. - */ - class GeneralContainerComponent extends React.Component { - render() { - return
{this.props.children}
; - } - } - - /** - * Notice how refs ownership is maintained even when injecting a component - * into a different parent. - */ - class TestRefsComponent extends React.Component { - container = null; - doReset = () => { - this.refs.myCounter.triggerReset(); - }; - - render() { - return ( -
(this.container = current)}> -
- Reset Me By Clicking This. -
- - - -
- ); - } - } - - container = document.createElement('div'); - document.body.appendChild(container); - - let testRefsComponent; - await expect(async () => { - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - { - testRefsComponent = current; - }} - />, - ); - }); - }).toErrorDev([ - 'Component "TestRefsComponent" contains the string ' + - 'ref "resetDiv". Support for string refs will be removed in a ' + - 'future major release. We recommend using useRef() or createRef() ' + - 'instead. Learn more about using refs safely ' + - 'here: https://react.dev/link/strict-mode-string-ref\n' + - ' in div (at **)\n' + - ' in div (at **)\n' + - ' in TestRefsComponent (at **)', - 'Component "ClickCounter" contains the string ' + - 'ref "clickLog0". Support for string refs will be removed in a ' + - 'future major release. We recommend using useRef() or createRef() ' + - 'instead. Learn more about using refs safely ' + - 'here: https://react.dev/link/strict-mode-string-ref\n' + - ' in div (at **)\n' + - ' in span (at **)\n' + - ' in ClickCounter (at **)', - ]); - - expect(testRefsComponent instanceof TestRefsComponent).toBe(true); - - const generalContainer = testRefsComponent.refs.myContainer; - expect(generalContainer instanceof GeneralContainerComponent).toBe(true); - - const counter = testRefsComponent.refs.myCounter; - expect(counter instanceof ClickCounter).toBe(true); - - return testRefsComponent; - }; - - /** - * Ensure that for every click log there is a corresponding ref (from the - * perspective of the injected ClickCounter component. - */ - // @gate !disableStringRefs - it('Should increase refs with an increase in divs', async () => { - const testRefsComponent = await renderTestRefsComponent(); - const clickIncrementer = - testRefsComponent.container.querySelector('.clickIncrementer'); - - expectClickLogsLengthToBe(testRefsComponent, 1); - - // After clicking the reset, there should still only be one click log ref. - testRefsComponent.refs.resetDiv.click(); - expectClickLogsLengthToBe(testRefsComponent, 1); - - // Begin incrementing clicks (and therefore refs). - await act(() => { - clickIncrementer.click(); - }); - expectClickLogsLengthToBe(testRefsComponent, 2); - - await act(() => { - clickIncrementer.click(); - }); - expectClickLogsLengthToBe(testRefsComponent, 3); - - // Now reset again - await act(() => { - testRefsComponent.refs.resetDiv.click(); - }); - expectClickLogsLengthToBe(testRefsComponent, 1); - }); -}); - /** * Tests that when a ref hops around children, we can track that correctly. */ @@ -320,32 +147,6 @@ describe('ref swapping', () => { expect(refCalled).toBe(1); }); - // @gate !disableStringRefs - it('coerces numbers to strings', async () => { - class A extends React.Component { - render() { - return
; - } - } - let a; - await expect(async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - - await act(() => { - root.render( (a = current)} />); - }); - }).toErrorDev([ - 'Component "A" contains the string ref "1". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in div (at **)\n' + - ' in A (at **)', - ]); - expect(a.refs[1].nodeName).toBe('DIV'); - }); - it('provides an error for invalid refs', async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); @@ -469,108 +270,6 @@ describe('root level refs', () => { }); }); -describe('creating element with string ref in constructor', () => { - class RefTest extends React.Component { - constructor(props) { - super(props); - this.p =

Hello!

; - } - - render() { - return
{this.p}
; - } - } - - // @gate !disableStringRefs && !__DEV__ - it('throws an error in prod', async () => { - await expect(async function () { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - - await act(() => { - root.render(); - }); - }) - // TODO: This throws an AggregateError. Need to update test infra to - // support matching against AggregateError. - .rejects.toThrowError(); - }); -}); - -describe('strings refs across renderers', () => { - // @gate !disableStringRefs - it('does not break', async () => { - class Parent extends React.Component { - render() { - // This component owns both refs. - return ( - } - child2={
} - /> - ); - } - } - - class Indirection extends React.Component { - componentDidUpdate() { - // One ref is being rendered later using another renderer copy. - jest.resetModules(); - const AnotherCopyOfReactDOM = require('react-dom'); - const AnotherCopyOfReactDOMClient = require('react-dom/client'); - const root = AnotherCopyOfReactDOMClient.createRoot(div2); - AnotherCopyOfReactDOM.flushSync(() => { - root.render(this.props.child2); - }); - } - render() { - // The other one is being rendered directly. - return this.props.child1; - } - } - - const div1 = document.createElement('div'); - const div2 = document.createElement('div'); - - const root = ReactDOMClient.createRoot(div1); - let inst; - await expect(async () => { - await act(() => { - root.render( - { - if (current !== null) { - inst = current; - } - }} - />, - ); - }); - }).toErrorDev([ - 'Component "Parent" contains the string ref "child1". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in div (at **)\n' + - ' in Indirection (at **)\n' + - ' in Parent (at **)', - ]); - - // Only the first ref has rendered yet. - expect(inst.refs.child1.tagName).toBe('DIV'); - expect(inst.refs.child1).toBe(div1.firstChild); - - // Now both refs should be rendered. - await act(() => { - root.render(); - }); - expect(inst.refs.child1.tagName).toBe('DIV'); - expect(inst.refs.child1).toBe(div1.firstChild); - expect(inst.refs.child2.tagName).toBe('DIV'); - expect(inst.refs.child2).toBe(div2.firstChild); - }); -}); - describe('refs return clean up function', () => { it('calls clean up function if it exists', async () => { const container = document.createElement('div'); diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 3e95e537e9ddd..4c1bf05e54046 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -35,7 +35,7 @@ import { ConcurrentRoot, LegacyRoot, } from 'react-reconciler/constants'; -import {disableLegacyMode, disableStringRefs} from 'shared/ReactFeatureFlags'; +import {disableLegacyMode} from 'shared/ReactFeatureFlags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import ReactVersion from 'shared/ReactVersion'; @@ -843,14 +843,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { value: null, }); return element; - } else if (!__DEV__ && disableStringRefs) { - return { - $$typeof: REACT_ELEMENT_TYPE, - type: type, - key: null, - ref: null, - props: props, - }; } else { return { $$typeof: REACT_ELEMENT_TYPE, @@ -858,8 +850,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { key: null, ref: null, props: props, - _owner: null, - _store: __DEV__ ? {} : undefined, }; } } diff --git a/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js b/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js index d329fb369cae3..0d6856f5d0ac1 100644 --- a/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js +++ b/packages/react-reconciler/src/ReactFiberAsyncDispatcher.js @@ -14,8 +14,6 @@ import {enableCache} from 'shared/ReactFeatureFlags'; import {readContext} from './ReactFiberNewContext'; import {CacheContext} from './ReactFiberCacheComponent'; -import {disableStringRefs} from 'shared/ReactFeatureFlags'; - import {current as currentOwner} from './ReactCurrentFiber'; function getCacheForType(resourceType: () => T): T { @@ -35,7 +33,7 @@ export const DefaultAsyncDispatcher: AsyncDispatcher = ({ getCacheForType, }: any); -if (__DEV__ || !disableStringRefs) { +if (__DEV__) { DefaultAsyncDispatcher.getOwner = (): null | Fiber => { return currentOwner; }; diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index efb34826c970d..0a5457d20c33b 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -110,7 +110,6 @@ import { enableRenderableContext, disableLegacyMode, disableDefaultPropsExceptForClasses, - disableStringRefs, enableOwnerStacks, } from 'shared/ReactFeatureFlags'; import isArray from 'shared/isArray'; @@ -1052,25 +1051,6 @@ function markRef(current: Fiber | null, workInProgress: Fiber) { ); } if (current === null || current.ref !== ref) { - if (!disableStringRefs && current !== null) { - const oldRef = current.ref; - const newRef = ref; - if ( - typeof oldRef === 'function' && - typeof newRef === 'function' && - typeof oldRef.__stringRef === 'string' && - oldRef.__stringRef === newRef.__stringRef && - oldRef.__stringRefType === newRef.__stringRefType && - oldRef.__stringRefOwner === newRef.__stringRefOwner - ) { - // Although this is a different callback, it represents the same - // string ref. To avoid breaking old Meta code that relies on string - // refs only being attached once, reuse the old ref. This will - // prevent us from detaching and reattaching the ref on each update. - workInProgress.ref = oldRef; - return; - } - } // Schedule a Ref effect workInProgress.flags |= Ref | RefStatic; } @@ -1388,7 +1368,7 @@ function finishClassComponent( const instance = workInProgress.stateNode; // Rerender - if (__DEV__ || !disableStringRefs) { + if (__DEV__) { setCurrentFiber(workInProgress); } let nextChildren; diff --git a/packages/react-reconciler/src/ReactFiberCommitEffects.js b/packages/react-reconciler/src/ReactFiberCommitEffects.js index 4d10c9ee6faff..70c49bc62fae5 100644 --- a/packages/react-reconciler/src/ReactFiberCommitEffects.js +++ b/packages/react-reconciler/src/ReactFiberCommitEffects.js @@ -18,7 +18,6 @@ import { enableProfilerNestedUpdatePhase, enableSchedulingProfiler, enableScopeAPI, - disableStringRefs, } from 'shared/ReactFeatureFlags'; import { ClassComponent, @@ -773,7 +772,7 @@ function commitAttachRef(finishedWork: Fiber) { if (__DEV__) { // TODO: We should move these warnings to happen during the render // phase (markRef). - if (disableStringRefs && typeof ref === 'string') { + if (typeof ref === 'string') { console.error('String refs are no longer supported.'); } else if (!ref.hasOwnProperty('current')) { console.error( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index aa5884444063d..1ea05dd010a81 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -40,7 +40,6 @@ import { enableInfiniteRenderLoopDetection, disableLegacyMode, disableDefaultPropsExceptForClasses, - disableStringRefs, enableSiblingPrerendering, enableComponentPerformanceTrack, } from 'shared/ReactFeatureFlags'; @@ -1732,7 +1731,7 @@ function handleThrow(root: FiberRoot, thrownValue: any): void { // These should be reset immediately because they're only supposed to be set // when React is executing user code. resetHooksAfterThrow(); - if (__DEV__ || !disableStringRefs) { + if (__DEV__) { resetCurrentFiber(); } @@ -1928,7 +1927,7 @@ function popDispatcher(prevDispatcher: any) { } function pushAsyncDispatcher() { - if (enableCache || __DEV__ || !disableStringRefs) { + if (enableCache || __DEV__) { const prevAsyncDispatcher = ReactSharedInternals.A; ReactSharedInternals.A = DefaultAsyncDispatcher; return prevAsyncDispatcher; @@ -1938,7 +1937,7 @@ function pushAsyncDispatcher() { } function popAsyncDispatcher(prevAsyncDispatcher: any) { - if (enableCache || __DEV__ || !disableStringRefs) { + if (enableCache || __DEV__) { ReactSharedInternals.A = prevAsyncDispatcher; } } @@ -2497,9 +2496,6 @@ function performUnitOfWork(unitOfWork: Fiber): void { } } - if (!disableStringRefs) { - resetCurrentFiber(); - } unitOfWork.memoizedProps = unitOfWork.pendingProps; if (next === null) { // If this doesn't spawn new work, complete the current work. @@ -2519,11 +2515,6 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void { next = replayBeginWork(unitOfWork); } - // The begin phase finished successfully without suspending. Return to the - // normal work loop. - if (!disableStringRefs) { - resetCurrentFiber(); - } unitOfWork.memoizedProps = unitOfWork.pendingProps; if (next === null) { // If this doesn't spawn new work, complete the current work. diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js index 1c98a9e9c7fbc..d91727525c96a 100644 --- a/packages/react-reconciler/src/ReactInternalTypes.js +++ b/packages/react-reconciler/src/ReactInternalTypes.js @@ -460,6 +460,6 @@ export type Dispatcher = { export type AsyncDispatcher = { getCacheForType: (resourceType: () => T) => T, - // DEV-only (or !disableStringRefs) + // DEV-only getOwner: () => null | Fiber | ReactComponentInfo | ComponentStackNode, }; diff --git a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js index 8fd5206c94ae4..78409c8e2a4eb 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberRefs-test.js @@ -85,35 +85,6 @@ describe('ReactFiberRefs', () => { expect(ref2.current).not.toBe(null); }); - // @gate !disableStringRefs - it('string ref props are converted to function refs', async () => { - let refProp; - function Child({ref}) { - refProp = ref; - return
; - } - - let owner; - class Owner extends React.Component { - render() { - owner = this; - return ; - } - } - - const root = ReactNoop.createRoot(); - await act(() => root.render()); - - // When string refs aren't disabled, string refs - // the receiving component receives a callback ref, not the original string. - // This behavior should never be shipped to open source; it's only here to - // allow Meta to keep using string refs temporarily while they finish - // migrating their codebase. - expect(typeof refProp === 'function').toBe(true); - expect(owner.refs.child.type).toBe('div'); - }); - - // @gate disableStringRefs it('throw if a string ref is passed to a ref-receiving component', async () => { let refProp; function Child({ref}) { diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js index 81f892b48e358..c4473c1774e93 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.js @@ -1334,38 +1334,4 @@ describe('ReactIncrementalSideEffects', () => { // TODO: Test that mounts, updates, refs, unmounts and deletions happen in the // expected way for aborted and resumed render life-cycles. - - // @gate !disableStringRefs - it('supports string refs', async () => { - let fooInstance = null; - - class Bar extends React.Component { - componentDidMount() { - this.test = 'test'; - } - render() { - return
; - } - } - - class Foo extends React.Component { - render() { - fooInstance = this; - return ; - } - } - - ReactNoop.render(); - await expect(async () => { - await waitForAll([]); - }).toErrorDev([ - 'Component "Foo" contains the string ref "bar". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in Bar (at **)\n' + - ' in Foo (at **)', - ]); - expect(fooInstance.refs.bar.test).toEqual('test'); - }); }); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js index ed349cde81f09..1a097ffbda564 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMEdge-test.js @@ -1001,9 +1001,7 @@ describe('ReactFlightDOMEdge', () => { expect(greeting._owner).toBe(lazyWrapper._debugInfo[0]); } else { expect(lazyWrapper._debugInfo).toBe(undefined); - expect(greeting._owner).toBe( - gate(flags => flags.disableStringRefs) ? undefined : null, - ); + expect(greeting._owner).toBe(undefined); } }); diff --git a/packages/react-server/src/ReactFizzAsyncDispatcher.js b/packages/react-server/src/ReactFizzAsyncDispatcher.js index 3a548ae138039..e4d940d463c23 100644 --- a/packages/react-server/src/ReactFizzAsyncDispatcher.js +++ b/packages/react-server/src/ReactFizzAsyncDispatcher.js @@ -10,8 +10,6 @@ import type {AsyncDispatcher} from 'react-reconciler/src/ReactInternalTypes'; import type {ComponentStackNode} from './ReactFizzComponentStack'; -import {disableStringRefs} from 'shared/ReactFeatureFlags'; - import {currentTaskInDEV} from './ReactFizzCurrentTask'; function getCacheForType(resourceType: () => T): T { @@ -29,8 +27,4 @@ if (__DEV__) { } return currentTaskInDEV.componentStack; }; -} else if (!disableStringRefs) { - DefaultAsyncDispatcher.getOwner = (): null => { - return null; - }; } diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index 7b881fdbe8cce..f245861ba0012 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -162,7 +162,6 @@ import { enableRenderableContext, disableDefaultPropsExceptForClasses, enableAsyncIterableChildren, - disableStringRefs, enableOwnerStacks, } from 'shared/ReactFeatureFlags'; @@ -4452,7 +4451,7 @@ export function performWork(request: Request): void { const prevDispatcher = ReactSharedInternals.H; ReactSharedInternals.H = HooksDispatcher; let prevAsyncDispatcher = null; - if (enableCache || __DEV__ || !disableStringRefs) { + if (enableCache || __DEV__) { prevAsyncDispatcher = ReactSharedInternals.A; ReactSharedInternals.A = DefaultAsyncDispatcher; } diff --git a/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js b/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js index f5f031a860ff9..00c1abf33292d 100644 --- a/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js +++ b/packages/react-server/src/flight/ReactFlightAsyncDispatcher.js @@ -7,14 +7,9 @@ * @flow */ -import type {ReactComponentInfo} from 'shared/ReactTypes'; - import type {AsyncDispatcher} from 'react-reconciler/src/ReactInternalTypes'; import {resolveRequest, getCache} from '../ReactFlightServer'; - -import {disableStringRefs} from 'shared/ReactFeatureFlags'; - import {resolveOwner} from './ReactFlightCurrentOwner'; function resolveCache(): Map { @@ -40,9 +35,4 @@ export const DefaultAsyncDispatcher: AsyncDispatcher = ({ if (__DEV__) { DefaultAsyncDispatcher.getOwner = resolveOwner; -} else if (!disableStringRefs) { - // Server Components never use string refs but the JSX runtime looks for it. - DefaultAsyncDispatcher.getOwner = (): null | ReactComponentInfo => { - return null; - }; } diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index 22ef789f4f6e9..3ad6aa0235188 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -551,25 +551,4 @@ describe 'ReactCoffeeScriptClass', -> ], ) - if !featureFlags.disableStringRefs - it 'supports string refs', -> - class Foo extends React.Component - render: -> - React.createElement(InnerComponent, - name: 'foo' - ref: 'inner' - ) - - ref = React.createRef() - expect(-> - test(React.createElement(Foo, ref: ref), 'DIV', 'foo') - ).toErrorDev([ - 'Component "Foo" contains the string ref "inner". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in _Class (at **)' - ]); - expect(ref.current.refs.inner.getName()).toBe 'foo' - undefined diff --git a/packages/react/src/__tests__/ReactCreateElement-test.js b/packages/react/src/__tests__/ReactCreateElement-test.js index 3ab5c34c3304d..392f89979e769 100644 --- a/packages/react/src/__tests__/ReactCreateElement-test.js +++ b/packages/react/src/__tests__/ReactCreateElement-test.js @@ -218,7 +218,7 @@ describe('ReactCreateElement', () => { } const root = ReactDOMClient.createRoot(document.createElement('div')); await act(() => root.render(React.createElement(Wrapper))); - if (__DEV__ || !gate(flags => flags.disableStringRefs)) { + if (__DEV__) { expect(element._owner.stateNode).toBe(instance); } else { expect('_owner' in element).toBe(false); diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 3ac0b18e8e753..eceeab18c5bb0 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -592,25 +592,4 @@ describe('ReactES6Class', () => { ]); }); } - - if (!require('shared/ReactFeatureFlags').disableStringRefs) { - it('supports string refs', () => { - class Foo extends React.Component { - render() { - return ; - } - } - const ref = React.createRef(); - expect(() => { - runTest(, 'DIV', 'foo'); - }).toErrorDev([ - 'Component "Foo" contains the string ref "inner". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in Inner (at **)', - ]); - expect(ref.current.refs.inner.getName()).toBe('foo'); - }); - } }); diff --git a/packages/react/src/__tests__/ReactElementClone-test.js b/packages/react/src/__tests__/ReactElementClone-test.js index 4e7d0c5ca2a2b..fb0bfe2df8d6b 100644 --- a/packages/react/src/__tests__/ReactElementClone-test.js +++ b/packages/react/src/__tests__/ReactElementClone-test.js @@ -270,49 +270,8 @@ describe('ReactElementClone', () => { const root = ReactDOMClient.createRoot(document.createElement('div')); await act(() => root.render()); - if (gate(flags => flags.disableStringRefs)) { - expect(component.childRef).toEqual({current: null}); - expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); - } else if (gate(flags => !flags.disableStringRefs)) { - expect(component.childRef).toEqual({current: null}); - expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); - } else { - // Not going to bother testing every possible combination. - } - }); - - // @gate !disableStringRefs - it('should steal the ref if a new string ref is specified without an owner', async () => { - // Regression test for this specific feature combination calling cloneElement on an element - // without an owner - await expect(async () => { - // create an element without an owner - const element = React.createElement('div', {id: 'some-id'}); - class Parent extends React.Component { - render() { - return {element}; - } - } - let child; - class Child extends React.Component { - render() { - child = this; - const clone = React.cloneElement(this.props.children, { - ref: 'xyz', - }); - return
{clone}
; - } - } - - const root = ReactDOMClient.createRoot(document.createElement('div')); - await act(() => root.render()); - expect(child.refs.xyz.tagName).toBe('DIV'); - }).toErrorDev([ - 'Component "Child" contains the string ref "xyz". Support for ' + - 'string refs will be removed in a future major release. We recommend ' + - 'using useRef() or createRef() instead. Learn more about using refs ' + - 'safely here: https://react.dev/link/strict-mode-string-ref', - ]); + expect(component.childRef).toEqual({current: null}); + expect(component.parentRef.current.xyzRef.current.tagName).toBe('SPAN'); }); it('should overwrite props', async () => { @@ -403,23 +362,12 @@ describe('ReactElementClone', () => { const clone = React.cloneElement(element, props); expect(clone.type).toBe(ComponentClass); expect(clone.key).toBe('12'); - if (gate(flags => flags.disableStringRefs)) { - expect(clone.props.ref).toBe('34'); - expect(() => expect(clone.ref).toBe('34')).toErrorDev( - 'Accessing element.ref was removed in React 19', - {withoutStack: true}, - ); - expect(clone.props).toEqual({foo: 'ef', ref: '34'}); - } else if (gate(flags => !flags.disableStringRefs)) { - expect(() => { - expect(clone.ref).toBe(element.ref); - }).toErrorDev('Accessing element.ref was removed in React 19', { - withoutStack: true, - }); - expect(clone.props).toEqual({foo: 'ef', ref: element.ref}); - } else { - // Not going to bother testing every possible combination. - } + expect(clone.props.ref).toBe('34'); + expect(() => expect(clone.ref).toBe('34')).toErrorDev( + 'Accessing element.ref was removed in React 19', + {withoutStack: true}, + ); + expect(clone.props).toEqual({foo: 'ef', ref: '34'}); if (__DEV__) { expect(Object.isFrozen(element)).toBe(true); expect(Object.isFrozen(element.props)).toBe(true); diff --git a/packages/react/src/__tests__/ReactStrictMode-test.js b/packages/react/src/__tests__/ReactStrictMode-test.js index 2ab9c3fa18c9b..97fcc1ec8c4ce 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.js @@ -956,55 +956,6 @@ describe('symbol checks', () => { }); }); -describe('string refs', () => { - beforeEach(() => { - jest.resetModules(); - React = require('react'); - ReactDOM = require('react-dom'); - ReactDOMClient = require('react-dom/client'); - act = require('internal-test-utils').act; - }); - - // @gate !disableStringRefs - it('should warn within a strict tree', async () => { - const {StrictMode} = React; - - class OuterComponent extends React.Component { - render() { - return ( - - - - ); - } - } - - class InnerComponent extends React.Component { - render() { - return null; - } - } - - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'Component "OuterComponent" contains the string ref "somestring". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in InnerComponent (at **)', - ); - - await act(() => { - root.render(); - }); - }); -}); - describe('context legacy', () => { beforeEach(() => { jest.resetModules(); diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index 4f4564d356a8c..00e3a8b3ff8a8 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -697,20 +697,4 @@ describe('ReactTypeScriptClass', function() { ] ); }); } - - if (!ReactFeatureFlags.disableStringRefs) { - it('supports string refs', function() { - const ref = React.createRef(); - expect(() => { - test(React.createElement(ClassicRefs, {ref: ref}), 'DIV', 'foo'); - }).toErrorDev([ - 'Component "ClassicRefs" contains the string ref "inner". ' + - 'Support for string refs will be removed in a future major release. ' + - 'We recommend using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: https://react.dev/link/strict-mode-string-ref\n' + - ' in Inner (at **)', - ]); - expect(ref.current.refs.inner.getName()).toBe('foo'); - }); - } }); diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js index 3722638ad9515..e0a689ec2404f 100644 --- a/packages/react/src/jsx/ReactJSXElement.js +++ b/packages/react/src/jsx/ReactJSXElement.js @@ -20,13 +20,9 @@ import isValidElementType from 'shared/isValidElementType'; import isArray from 'shared/isArray'; import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame'; import { - disableStringRefs, disableDefaultPropsExceptForClasses, enableOwnerStacks, } from 'shared/ReactFeatureFlags'; -import {checkPropStringCoercion} from 'shared/CheckStringCoercion'; -import {ClassComponent} from 'react-reconciler/src/ReactWorkTags'; -import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber'; const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference'); @@ -59,7 +55,7 @@ function getTaskName(type) { } function getOwner() { - if (__DEV__ || !disableStringRefs) { + if (__DEV__) { const dispatcher = ReactSharedInternals.A; if (dispatcher === null) { return null; @@ -70,17 +66,13 @@ function getOwner() { } let specialPropKeyWarningShown; -let didWarnAboutStringRefs; let didWarnAboutElementRef; let didWarnAboutOldJSXRuntime; if (__DEV__) { - didWarnAboutStringRefs = {}; didWarnAboutElementRef = {}; } -const enableFastJSXWithoutStringRefs = disableStringRefs; - function hasValidRef(config) { if (__DEV__) { if (hasOwnProperty.call(config, 'ref')) { @@ -105,35 +97,6 @@ function hasValidKey(config) { return config.key !== undefined; } -function warnIfStringRefCannotBeAutoConverted(config, self) { - if (__DEV__) { - let owner; - if ( - !disableStringRefs && - typeof config.ref === 'string' && - (owner = getOwner()) && - self && - owner.stateNode !== self - ) { - const componentName = getComponentNameFromType(owner.type); - - if (!didWarnAboutStringRefs[componentName]) { - console.error( - 'Component "%s" contains the string ref "%s". ' + - 'Support for string refs will be removed in a future major release. ' + - 'This case cannot be automatically converted to an arrow function. ' + - 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref', - getComponentNameFromType(owner.type), - config.ref, - ); - didWarnAboutStringRefs[componentName] = true; - } - } - } -} - function defineKeyPropWarningGetter(props, displayName) { if (__DEV__) { const warnAboutAccessingKey = function () { @@ -259,22 +222,8 @@ function ReactElement( value: null, }); } - } else if (!__DEV__ && disableStringRefs) { - // In prod, `ref` is a regular property and _owner doesn't exist. - element = { - // This tag allows us to uniquely identify this as a React Element - $$typeof: REACT_ELEMENT_TYPE, - - // Built-in properties that belong on the element - type, - key, - ref, - - props, - }; } else { - // In prod, `ref` is a regular property. It will be removed in a - // future release. + // In prod, `ref` is a regular property and _owner doesn't exist. element = { // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, @@ -285,9 +234,6 @@ function ReactElement( ref, props, - - // Record the component responsible for creating this element. - _owner: owner, }; } @@ -368,10 +314,7 @@ export function jsxProd(type, config, maybeKey) { } let props; - if ( - (enableFastJSXWithoutStringRefs || !('ref' in config)) && - !('key' in config) - ) { + if (!('key' in config)) { // If key was not spread in, we can reuse the original props object. This // only works for `jsx`, not `createElement`, because `jsx` is a compiler // target and the compiler always passes a new object. For `createElement`, @@ -390,11 +333,7 @@ export function jsxProd(type, config, maybeKey) { for (const propName in config) { // Skip over reserved prop names if (propName !== 'key') { - if (!disableStringRefs && propName === 'ref') { - props.ref = coerceStringRef(config[propName], getOwner(), type); - } else { - props[propName] = config[propName]; - } + props[propName] = config[propName]; } } } @@ -637,17 +576,8 @@ function jsxDEVImpl( key = '' + config.key; } - if (!disableStringRefs) { - if (hasValidRef(config)) { - warnIfStringRefCannotBeAutoConverted(config, self); - } - } - let props; - if ( - (enableFastJSXWithoutStringRefs || !('ref' in config)) && - !('key' in config) - ) { + if (!('key' in config)) { // If key was not spread in, we can reuse the original props object. This // only works for `jsx`, not `createElement`, because `jsx` is a compiler // target and the compiler always passes a new object. For `createElement`, @@ -666,11 +596,7 @@ function jsxDEVImpl( for (const propName in config) { // Skip over reserved prop names if (propName !== 'key') { - if (!disableStringRefs && propName === 'ref') { - props.ref = coerceStringRef(config[propName], getOwner(), type); - } else { - props[propName] = config[propName]; - } + props[propName] = config[propName]; } } } @@ -800,11 +726,6 @@ export function createElement(type, config, children) { } } - if (__DEV__ && !disableStringRefs) { - if (hasValidRef(config)) { - warnIfStringRefCannotBeAutoConverted(config, config.__self); - } - } if (hasValidKey(config)) { if (__DEV__) { checkKeyStringCoercion(config.key); @@ -825,11 +746,7 @@ export function createElement(type, config, children) { propName !== '__self' && propName !== '__source' ) { - if (!disableStringRefs && propName === 'ref') { - props.ref = coerceStringRef(config[propName], getOwner(), type); - } else { - props[propName] = config[propName]; - } + props[propName] = config[propName]; } } } @@ -889,7 +806,7 @@ export function cloneAndReplaceKey(oldElement, newKey) { newKey, undefined, undefined, - !__DEV__ && disableStringRefs ? undefined : oldElement._owner, + !__DEV__ ? undefined : oldElement._owner, oldElement.props, __DEV__ && enableOwnerStacks ? oldElement._debugStack : undefined, __DEV__ && enableOwnerStacks ? oldElement._debugTask : undefined, @@ -921,11 +838,11 @@ export function cloneElement(element, config, children) { let key = element.key; // Owner will be preserved, unless ref is overridden - let owner = !__DEV__ && disableStringRefs ? undefined : element._owner; + let owner = !__DEV__ ? undefined : element._owner; if (config != null) { if (hasValidRef(config)) { - owner = __DEV__ || !disableStringRefs ? getOwner() : undefined; + owner = __DEV__ ? getOwner() : undefined; } if (hasValidKey(config)) { if (__DEV__) { @@ -969,11 +886,7 @@ export function cloneElement(element, config, children) { // Resolve default props props[propName] = defaultProps[propName]; } else { - if (!disableStringRefs && propName === 'ref') { - props.ref = coerceStringRef(config[propName], owner, element.type); - } else { - props[propName] = config[propName]; - } + props[propName] = config[propName]; } } } @@ -1173,99 +1086,3 @@ function getCurrentComponentErrorInfo(parentType) { return info; } } - -function coerceStringRef(mixedRef, owner, type) { - if (disableStringRefs) { - return mixedRef; - } - - let stringRef; - if (typeof mixedRef === 'string') { - stringRef = mixedRef; - } else { - if (typeof mixedRef === 'number' || typeof mixedRef === 'boolean') { - if (__DEV__) { - checkPropStringCoercion(mixedRef, 'ref'); - } - stringRef = '' + mixedRef; - } else { - return mixedRef; - } - } - - const callback = stringRefAsCallbackRef.bind(null, stringRef, type, owner); - // This is used to check whether two callback refs conceptually represent - // the same string ref, and can therefore be reused by the reconciler. Needed - // for backwards compatibility with old Meta code that relies on string refs - // not being reattached on every render. - callback.__stringRef = stringRef; - callback.__type = type; - callback.__owner = owner; - return callback; -} - -function stringRefAsCallbackRef(stringRef, type, owner, value) { - if (disableStringRefs) { - return; - } - if (!owner) { - throw new Error( - `Element ref was specified as a string (${stringRef}) but no owner was set. This could happen for one of` + - ' the following reasons:\n' + - '1. You may be adding a ref to a function component\n' + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - '3. You have multiple copies of React loaded\n' + - 'See https://react.dev/link/refs-must-have-owner for more information.', - ); - } - if (owner.tag !== ClassComponent) { - throw new Error( - 'Function components cannot have string refs. ' + - 'We recommend using useRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref', - ); - } - - if (__DEV__) { - if ( - // Will already warn with "Function components cannot be given refs" - !(typeof type === 'function' && !isReactClass(type)) - ) { - const componentName = getComponentNameFromFiber(owner) || 'Component'; - if (!didWarnAboutStringRefs[componentName]) { - if (__DEV__) { - console.error( - 'Component "%s" contains the string ref "%s". Support for string refs ' + - 'will be removed in a future major release. We recommend using ' + - 'useRef() or createRef() instead. ' + - 'Learn more about using refs safely here: ' + - 'https://react.dev/link/strict-mode-string-ref', - componentName, - stringRef, - ); - } - didWarnAboutStringRefs[componentName] = true; - } - } - } - - const inst = owner.stateNode; - if (!inst) { - throw new Error( - `Missing owner for string ref ${stringRef}. This error is likely caused by a ` + - 'bug in React. Please file an issue.', - ); - } - - const refs = inst.refs; - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; - } -} - -function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; -} diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index d1159e60373cd..44d6e8629db83 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -208,8 +208,6 @@ export const enableFilterEmptyStringAttributesDOM = true; // Disabled caching behavior of `react/cache` in client runtimes. export const disableClientCache = true; -export const disableStringRefs = true; - // Warn on any usage of ReactTestRenderer export const enableReactTestRendererWarning = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 7e63db5ef45ed..a553c275fed8f 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -41,7 +41,6 @@ export const disableLegacyContext = false; export const disableLegacyContextForFunctionComponents = false; export const disableLegacyMode = false; export const disableSchedulerTimeoutInWorkLoop = false; -export const disableStringRefs = true; export const disableTextareaChildren = false; export const enableAsyncActions = true; export const enableAsyncDebugInfo = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 644b23b46afae..d59e3f9698d4a 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -30,7 +30,6 @@ export const disableLegacyContext = true; export const disableLegacyContextForFunctionComponents = true; export const disableLegacyMode = false; export const disableSchedulerTimeoutInWorkLoop = false; -export const disableStringRefs = true; export const disableTextareaChildren = false; export const enableAsyncActions = true; export const enableAsyncDebugInfo = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 2946d5efa11bc..c27b2d6913dcd 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -90,7 +90,6 @@ export const enableSiblingPrerendering = false; // We really need to get rid of this whole module. Any test renderer specific // flags should be handled by the Fiber config. // const __NEXT_MAJOR__ = __EXPERIMENTAL__; -export const disableStringRefs = true; export const disableLegacyMode = true; export const disableLegacyContext = true; export const disableLegacyContextForFunctionComponents = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 1d505aaf56b9d..170145c93db63 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -22,7 +22,6 @@ export const disableLegacyContext = false; export const disableLegacyContextForFunctionComponents = false; export const disableLegacyMode = false; export const disableSchedulerTimeoutInWorkLoop = false; -export const disableStringRefs = true; export const disableTextareaChildren = false; export const enableAsyncActions = true; export const enableAsyncDebugInfo = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 8e9e8f0ca2d58..46e939fd7319a 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -82,8 +82,6 @@ export const disableClientCache = true; export const enableServerComponentLogs = true; export const enableInfiniteRenderLoopDetection = false; -export const disableStringRefs = true; - export const enableReactTestRendererWarning = false; export const disableLegacyMode = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index dac110129ef53..32a39121441b6 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -52,7 +52,6 @@ export const enableSuspenseAvoidThisFallback = true; export const enableSuspenseAvoidThisFallbackFizz = false; export const disableIEWorkarounds = true; -export const disableStringRefs = true; export const enableCPUSuspense = true; export const enableUseMemoCacheHook = true; export const enableUseEffectEventHook = true; From 682a103cde99a3091850d1c27de8846b5d14e803 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Thu, 7 Nov 2024 09:05:31 -0500 Subject: [PATCH 359/426] [www] set disableLegacyMode to true (#31439) --- packages/shared/forks/ReactFeatureFlags.www-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.www.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index 8a82b7f55241b..482ebb03c6310 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -16,7 +16,6 @@ export const alwaysThrottleRetries = true; export const disableDefaultPropsExceptForClasses = __VARIANT__; export const disableLegacyContextForFunctionComponents = __VARIANT__; -export const disableLegacyMode = __VARIANT__; export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 32a39121441b6..013092c1c4eb6 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -117,8 +117,7 @@ export const enableServerComponentLogs = true; export const enableReactTestRendererWarning = false; export const useModernStrictMode = true; -export const disableLegacyMode: boolean = - __EXPERIMENTAL__ || dynamicFeatureFlags.disableLegacyMode; +export const disableLegacyMode = true; export const enableOwnerStacks = false; export const enableShallowPropDiffing = false; From 5c56b873efb300b4d1afc4ba6f16acf17e4e5800 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Thu, 7 Nov 2024 14:53:44 +0000 Subject: [PATCH 360/426] Update React Native shims to use export syntax (#31426) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary I'm working to get the main `react-native` package parsable by modern Flow tooling (both `flow-bundler`, `flow-api-translator`), and one blocker is legacy `module.exports` syntax. This diff updates files which are [synced to `react-native`](https://github.com/facebook/react-native/tree/main/packages/react-native/Libraries/Renderer/shims) from this repo. ## How did you test this change? Files were pasted into `react-native-github` under fbsource, where Flow validates ✅. --- scripts/rollup/shims/react-native/ReactFabric.js | 4 ++-- scripts/rollup/shims/react-native/ReactFeatureFlags.js | 2 +- scripts/rollup/shims/react-native/ReactNative.js | 4 ++-- .../shims/react-native/createReactNativeComponentClass.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/rollup/shims/react-native/ReactFabric.js b/scripts/rollup/shims/react-native/ReactFabric.js index 61f6d726887b3..69fb77af69a86 100644 --- a/scripts/rollup/shims/react-native/ReactFabric.js +++ b/scripts/rollup/shims/react-native/ReactFabric.js @@ -15,7 +15,7 @@ import {BatchedBridge} from 'react-native/Libraries/ReactPrivate/ReactNativePriv import type {ReactFabricType} from './ReactNativeTypes'; -let ReactFabric; +let ReactFabric: ReactFabricType; if (__DEV__) { ReactFabric = require('../implementations/ReactFabric-dev'); @@ -29,4 +29,4 @@ if (global.RN$Bridgeless !== true) { BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); } -module.exports = (ReactFabric: ReactFabricType); +export default ReactFabric; diff --git a/scripts/rollup/shims/react-native/ReactFeatureFlags.js b/scripts/rollup/shims/react-native/ReactFeatureFlags.js index 69e6f48b68a34..3f8f278e972a4 100644 --- a/scripts/rollup/shims/react-native/ReactFeatureFlags.js +++ b/scripts/rollup/shims/react-native/ReactFeatureFlags.js @@ -15,4 +15,4 @@ const ReactFeatureFlags = { debugRenderPhaseSideEffects: false, }; -module.exports = ReactFeatureFlags; +export default ReactFeatureFlags; diff --git a/scripts/rollup/shims/react-native/ReactNative.js b/scripts/rollup/shims/react-native/ReactNative.js index d0297cc9a61cb..82c062bb85123 100644 --- a/scripts/rollup/shims/react-native/ReactNative.js +++ b/scripts/rollup/shims/react-native/ReactNative.js @@ -12,7 +12,7 @@ import type {ReactNativeType} from './ReactNativeTypes'; -let ReactNative; +let ReactNative: ReactNativeType; if (__DEV__) { ReactNative = require('../implementations/ReactNativeRenderer-dev'); @@ -20,4 +20,4 @@ if (__DEV__) { ReactNative = require('../implementations/ReactNativeRenderer-prod'); } -module.exports = (ReactNative: ReactNativeType); +export default ReactNative; diff --git a/scripts/rollup/shims/react-native/createReactNativeComponentClass.js b/scripts/rollup/shims/react-native/createReactNativeComponentClass.js index 388991e45b545..42ea979daef3e 100644 --- a/scripts/rollup/shims/react-native/createReactNativeComponentClass.js +++ b/scripts/rollup/shims/react-native/createReactNativeComponentClass.js @@ -31,4 +31,4 @@ const createReactNativeComponentClass = function ( return register(name, callback); }; -module.exports = createReactNativeComponentClass; +export default createReactNativeComponentClass; From 989af12f72080c17db03ead91d99b6394a215564 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Fri, 8 Nov 2024 12:38:41 -0500 Subject: [PATCH 361/426] Make prerendering always non-blocking with fix (#31452) We've previously failed to land this change due to some internal apps seeing infinite render loops due to external store state updates during render. It turns out that since the `renderWasConcurrent` var was moved into the do block, the sync render triggered from the external store check was stuck with a `RootSuspended` `exitStatus`. So this is not unique to sibling prerendering but more generally related to how we handle update to a sync external store during render. We've tested this build against local repros which now render without crashes. We will try to add a unit test to cover the scenario as well. --------- Co-authored-by: Andrew Clark Co-authored-by: Rick Hanlon --- .../src/__tests__/ReactDOMFiberAsync-test.js | 2 +- .../react-reconciler/src/ReactFiberLane.js | 6 +- .../src/ReactFiberRootScheduler.js | 20 +- .../src/ReactFiberWorkLoop.js | 298 +++++++++++------- .../src/__tests__/ReactDeferredValue-test.js | 12 + .../ReactSiblingPrerendering-test.js | 71 +++++ .../__tests__/useSyncExternalStore-test.js | 148 ++++++++- 7 files changed, 428 insertions(+), 129 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index ee843996bef1c..027099d54707c 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -744,7 +744,7 @@ describe('ReactDOMFiberAsync', () => { // Because it suspended, it remains on the current path expect(div.textContent).toBe('/path/a'); }); - assertLog([]); + assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []); await act(async () => { resolvePromise(); diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index 7d6bfd16e8aa0..b98019046e3c2 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -765,12 +765,14 @@ export function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didSkipSuspendedSiblings: boolean, + didAttemptEntireTree: boolean, ) { + // TODO: Split this into separate functions for marking the root at the end of + // a render attempt versus suspending while the root is still in progress. root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; - if (enableSiblingPrerendering && !didSkipSuspendedSiblings) { + if (enableSiblingPrerendering && didAttemptEntireTree) { // Mark these lanes as warm so we know there's nothing else to work on. root.warmLanes |= suspendedLanes; } else { diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 9f267e8345e39..39f6f466ed983 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -18,6 +18,7 @@ import { disableSchedulerTimeoutInWorkLoop, enableProfilerTimer, enableProfilerNestedUpdatePhase, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import { NoLane, @@ -29,6 +30,7 @@ import { markStarvedLanesAsExpired, claimNextTransitionLane, getNextLanesToFlushSync, + checkIfRootIsPrerendering, } from './ReactFiberLane'; import { CommitContext, @@ -206,7 +208,10 @@ function flushSyncWorkAcrossRoots_impl( ? workInProgressRootRenderLanes : NoLanes, ); - if (includesSyncLane(nextLanes)) { + if ( + includesSyncLane(nextLanes) && + !checkIfRootIsPrerendering(root, nextLanes) + ) { // This root has pending sync work. Flush it now. didPerformSomeWork = true; performSyncWorkOnRoot(root, nextLanes); @@ -341,7 +346,13 @@ function scheduleTaskForRootDuringMicrotask( } // Schedule a new callback in the host environment. - if (includesSyncLane(nextLanes)) { + if ( + includesSyncLane(nextLanes) && + // If we're prerendering, then we should use the concurrent work loop + // even if the lanes are synchronous, so that prerendering never blocks + // the main thread. + !(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes)) + ) { // Synchronous work is always flushed at the end of the microtask, so we // don't need to schedule an additional task. if (existingCallbackNode !== null) { @@ -375,9 +386,10 @@ function scheduleTaskForRootDuringMicrotask( let schedulerPriorityLevel; switch (lanesToEventPriority(nextLanes)) { + // Scheduler does have an "ImmediatePriority", but now that we use + // microtasks for sync work we no longer use that. Any sync work that + // reaches this path is meant to be time sliced. case DiscreteEventPriority: - schedulerPriorityLevel = ImmediateSchedulerPriority; - break; case ContinuousEventPriority: schedulerPriorityLevel = UserBlockingSchedulerPriority; break; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 1ea05dd010a81..bd30492fc0d0e 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -764,11 +764,12 @@ export function scheduleUpdateOnFiber( // The incoming update might unblock the current render. Interrupt the // current attempt and restart from the top. prepareFreshStack(root, NoLanes); + const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } @@ -831,11 +832,12 @@ export function scheduleUpdateOnFiber( // effect of interrupting the current render and switching to the update. // TODO: Make sure this doesn't override pings that happen while we've // already started rendering. + const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } } @@ -897,100 +899,121 @@ export function performWorkOnRoot( // for too long ("expired" work, to prevent starvation), or we're in // sync-updates-by-default mode. const shouldTimeSlice = - !forceSync && - !includesBlockingLane(lanes) && - !includesExpiredLane(root, lanes); + (!forceSync && + !includesBlockingLane(lanes) && + !includesExpiredLane(root, lanes)) || + // If we're prerendering, then we should use the concurrent work loop + // even if the lanes are synchronous, so that prerendering never blocks + // the main thread. + // TODO: We should consider doing this whenever a sync lane is suspended, + // even for regular pings. + (enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes)); + let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); - - if (exitStatus !== RootInProgress) { - let renderWasConcurrent = shouldTimeSlice; - do { - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended( + : renderRootSync(root, lanes, true); + + let renderWasConcurrent = shouldTimeSlice; + + do { + if (exitStatus === RootInProgress) { + // Render phase is still in progress. + if ( + enableSiblingPrerendering && + workInProgressRootIsPrerendering && + !shouldTimeSlice + ) { + // We're in prerendering mode, but time slicing is not enabled. This + // happens when something suspends during a synchronous update. Exit the + // the work loop. When we resume, we'll use the concurrent work loop so + // that prerendering is non-blocking. + // + // Mark the root as suspended. Usually we do this at the end of the + // render phase, but we do it here so that we resume in + // prerendering mode. + // TODO: Consider always calling markRootSuspended immediately. + // Needs to be *after* we attach a ping listener, though. + const didAttemptEntireTree = false; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + } + break; + } else if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + } else { + // The render completed. + + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + const finishedWork: Fiber = (root.current.alternate: any); + if ( + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) + ) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes, false); + // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + renderWasConcurrent = false; + // Need to check the exit status again. + continue; + } + + // Check if something threw + if ( + (disableLegacyMode || root.tag !== LegacyRoot) && + exitStatus === RootErrored + ) { + const lanesThatJustErrored = lanes; + const errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, - lanes, - NoLane, - workInProgressRootDidSkipSuspendedSiblings, + lanesThatJustErrored, ); - } else { - // The render completed. - - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - const finishedWork: Fiber = (root.current.alternate: any); - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); - // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - renderWasConcurrent = false; - // Need to check the exit status again. - continue; - } - - // Check if something threw - if ( - (disableLegacyMode || root.tag !== LegacyRoot) && - exitStatus === RootErrored - ) { - const lanesThatJustErrored = lanes; - const errorRetryLanes = getLanesToRetrySynchronouslyOnError( + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( root, lanesThatJustErrored, + errorRetryLanes, ); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - lanesThatJustErrored, - errorRetryLanes, - ); - renderWasConcurrent = false; - // Need to check the exit status again. - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } else { - // The root errored yet again. Proceed to commit the tree. - } + renderWasConcurrent = false; + // Need to check the exit status again. + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; + } else { + // The root errored yet again. Proceed to commit the tree. } } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended( - root, - lanes, - NoLane, - workInProgressRootDidSkipSuspendedSiblings, - ); - break; - } - - // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. - finishConcurrentRender(root, exitStatus, finishedWork, lanes); } - break; - } while (true); - } + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + // Since this is a fatal error, we're going to pretend we attempted + // the entire tree, to avoid scheduling a prerender. + const didAttemptEntireTree = true; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + break; + } + + // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } + break; + } while (true); ensureRootIsScheduled(root); } @@ -1023,7 +1046,7 @@ function recoverFromConcurrentError( rootWorkInProgress.flags |= ForceClientRender; } - const exitStatus = renderRootSync(root, errorRetryLanes); + const exitStatus = renderRootSync(root, errorRetryLanes, false); if (exitStatus !== RootErrored) { // Successfully finished rendering on retry @@ -1107,11 +1130,13 @@ function finishConcurrentRender( // This is a transition, so we should exit without committing a // placeholder and without scheduling a timeout. Delay indefinitely // until we receive more data. + const didAttemptEntireTree = + !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); return; } @@ -1167,11 +1192,13 @@ function finishConcurrentRender( // Don't bother with a very short suspense time. if (msUntilTimeout > 10) { + const didAttemptEntireTree = + !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); const nextLanes = getNextLanes(root, NoLanes); @@ -1285,7 +1312,8 @@ function commitRootWhenReady( completedRenderEndTime, ), ); - markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings); + const didAttemptEntireTree = !didSkipSuspendedSiblings; + markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree); return; } } @@ -1408,7 +1436,7 @@ function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didSkipSuspendedSiblings: boolean, + didAttemptEntireTree: boolean, ) { // When suspending, we should always exclude lanes that were pinged or (more // rarely, since we try to avoid it) updated during the render phase. @@ -1417,12 +1445,7 @@ function markRootSuspended( suspendedLanes, workInProgressRootInterleavedUpdatedLanes, ); - _markRootSuspended( - root, - suspendedLanes, - spawnedLane, - didSkipSuspendedSiblings, - ); + _markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree); } export function flushRoot(root: FiberRoot, lanes: Lanes) { @@ -1964,7 +1987,12 @@ export function renderDidSuspendDelayIfPossible(): void { if ( !workInProgressRootDidSkipSuspendedSiblings && - !includesBlockingLane(workInProgressRootRenderLanes) + // Check if the root will be blocked from committing. + // TODO: Consider aligning this better with the rest of the logic. Maybe + // we should only set the exit status to RootSuspendedWithDelay if this + // condition is true? And remove the equivalent checks elsewhere. + (includesOnlyTransitions(workInProgressRootRenderLanes) || + getSuspenseHandler() === null) ) { // This render may not have originally been scheduled as a prerender, but // something suspended inside the visible part of the tree, which means we @@ -1990,11 +2018,12 @@ export function renderDidSuspendDelayIfPossible(): void { // pinged or updated while we were rendering. // TODO: Consider unwinding immediately, using the // SuspendedOnHydration mechanism. + const didAttemptEntireTree = false; markRootSuspended( workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } } @@ -2024,7 +2053,11 @@ export function renderHasNotSuspendedYet(): boolean { // TODO: Over time, this function and renderRootConcurrent have become more // and more similar. Not sure it makes sense to maintain forked paths. Consider // unifying them again. -function renderRootSync(root: FiberRoot, lanes: Lanes) { +function renderRootSync( + root: FiberRoot, + lanes: Lanes, + shouldYieldForPrerendering: boolean, +): RootExitStatus { const prevExecutionContext = executionContext; executionContext |= RenderContext; const prevDispatcher = pushDispatcher(root.containerInfo); @@ -2064,6 +2097,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { } let didSuspendInShell = false; + let exitStatus = workInProgressRootExitStatus; outer: do { try { if ( @@ -2085,16 +2119,37 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { // Selective hydration. An update flowed into a dehydrated tree. // Interrupt the current render so the work loop can switch to the // hydration lane. + // TODO: I think we might not need to reset the stack here; we can + // just yield and reset the stack when we re-enter the work loop, + // like normal. resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; + exitStatus = RootDidNotComplete; break outer; } case SuspendedOnImmediate: - case SuspendedOnData: { - if (!didSuspendInShell && getSuspenseHandler() === null) { + case SuspendedOnData: + case SuspendedOnDeprecatedThrowPromise: { + if (getSuspenseHandler() === null) { didSuspendInShell = true; } - // Intentional fallthrough + const reason = workInProgressSuspendedReason; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason); + if ( + enableSiblingPrerendering && + shouldYieldForPrerendering && + workInProgressRootIsPrerendering + ) { + // We've switched into prerendering mode. This implies that we + // suspended outside of a Suspense boundary, which means this + // render will be blocked from committing. Yield to the main + // thread so we can switch to prerendering using the concurrent + // work loop. + exitStatus = RootInProgress; + break outer; + } + break; } default: { // Unwind then continue with the normal work loop. @@ -2107,6 +2162,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { } } workLoopSync(); + exitStatus = workInProgressRootExitStatus; break; } catch (thrownValue) { handleThrow(root, thrownValue); @@ -2129,14 +2185,6 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { popDispatcher(prevDispatcher); popAsyncDispatcher(prevAsyncDispatcher); - if (workInProgress !== null) { - // This is a sync render, so we should have finished the whole tree. - throw new Error( - 'Cannot commit an incomplete root. This error is likely caused by a ' + - 'bug in React. Please file an issue.', - ); - } - if (__DEV__) { if (enableDebugTracing) { logRenderStopped(); @@ -2147,14 +2195,21 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { markRenderStopped(); } - // Set this to null to indicate there's no in-progress render. - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; + if (workInProgress !== null) { + // Did not complete the tree. This can happen if something suspended in + // the shell. + } else { + // Normal case. We completed the whole tree. + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; - // It's safe to process the queue now that the render phase is complete. - finishQueueingConcurrentUpdates(); + // It's safe to process the queue now that the render phase is complete. + finishQueueingConcurrentUpdates(); + } - return workInProgressRootExitStatus; + return exitStatus; } // The work loop is an extremely hot path. Tell Closure not to inline it. @@ -2200,9 +2255,7 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) { // // If we were previously in prerendering mode, check if we received any new // data during an interleaved event. - if (workInProgressRootIsPrerendering) { - workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); - } + workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); } if (__DEV__) { @@ -3744,6 +3797,9 @@ function pingSuspendedRoot( // the logic of whether or not a root suspends once it completes. // TODO: If we're rendering sync either due to Sync, Batched or expired, // we should probably never restart. + // TODO: Attach different listeners depending on whether the listener was + // attached during prerendering. Prerender pings should not interrupt + // normal renders. // If we're suspended with delay, or if it's a retry, we'll always suspend // so we can always restart. diff --git a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js index fd03ba7310f83..8ca142cb50517 100644 --- a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js +++ b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js @@ -420,6 +420,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); @@ -459,6 +463,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); @@ -533,6 +541,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); diff --git a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js index 37d907b0fdc65..235e8df2201de 100644 --- a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js @@ -479,4 +479,75 @@ describe('ReactSiblingPrerendering', () => { assertLog([]); }, ); + + it( + 'when a synchronous update suspends outside a boundary, the resulting' + + 'prerender is concurrent', + async () => { + function App() { + return ( + <> + + + + + + + ); + } + + const root = ReactNoop.createRoot(); + // Mount the root synchronously + ReactNoop.flushSync(() => root.render()); + + // Synchronously render everything until we suspend in the shell + assertLog(['A', 'B', 'Suspend! [Async]']); + + if (gate('enableSiblingPrerendering')) { + // The rest of the siblings begin to prerender concurrently. Notice + // that we don't unwind here; we pick up where we left off above. + await waitFor(['C']); + await waitFor(['D']); + } + + assertLog([]); + expect(root).toMatchRenderedOutput(null); + + await resolveText('Async'); + assertLog(['A', 'B', 'Async', 'C', 'D']); + expect(root).toMatchRenderedOutput('ABAsyncCD'); + }, + ); + + it('restart a suspended sync render if something suspends while prerendering the siblings', async () => { + function App() { + return ( + <> + + + + + + + ); + } + + const root = ReactNoop.createRoot(); + // Mount the root synchronously + ReactNoop.flushSync(() => root.render()); + + // Synchronously render everything until we suspend in the shell + assertLog(['A', 'B', 'Suspend! [Async]']); + + if (gate('enableSiblingPrerendering')) { + // The rest of the siblings begin to prerender concurrently + await waitFor(['C']); + } + + // While we're prerendering, Async resolves. We should unwind and + // start over, rather than continue prerendering D. + await resolveText('Async'); + assertLog(['A', 'B', 'Async', 'C', 'D']); + expect(root).toMatchRenderedOutput('ABAsyncCD'); + }); }); diff --git a/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js b/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js index a61b5e49bb890..a5c6a6995d718 100644 --- a/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js +++ b/packages/react-reconciler/src/__tests__/useSyncExternalStore-test.js @@ -24,6 +24,9 @@ let startTransition; let waitFor; let waitForAll; let assertLog; +let Suspense; +let useMemo; +let textCache; // This tests the native useSyncExternalStore implementation, not the shim. // Tests that apply to both the native implementation and the shim should go @@ -45,7 +48,9 @@ describe('useSyncExternalStore', () => { use = React.use; useSyncExternalStore = React.useSyncExternalStore; startTransition = React.startTransition; - + Suspense = React.Suspense; + useMemo = React.useMemo; + textCache = new Map(); const InternalTestUtils = require('internal-test-utils'); waitFor = InternalTestUtils.waitFor; waitForAll = InternalTestUtils.waitForAll; @@ -54,6 +59,60 @@ describe('useSyncExternalStore', () => { act = require('internal-test-utils').act; }); + function resolveText(text) { + const record = textCache.get(text); + if (record === undefined) { + const newRecord = { + status: 'resolved', + value: text, + }; + textCache.set(text, newRecord); + } else if (record.status === 'pending') { + const thenable = record.value; + record.status = 'resolved'; + record.value = text; + thenable.pings.forEach(t => t()); + } + } + function readText(text) { + const record = textCache.get(text); + if (record !== undefined) { + switch (record.status) { + case 'pending': + throw record.value; + case 'rejected': + throw record.value; + case 'resolved': + return record.value; + } + } else { + const thenable = { + pings: [], + then(resolve) { + if (newRecord.status === 'pending') { + thenable.pings.push(resolve); + } else { + Promise.resolve().then(() => resolve(newRecord.value)); + } + }, + }; + + const newRecord = { + status: 'pending', + value: thenable, + }; + textCache.set(text, newRecord); + + throw thenable; + } + } + + function AsyncText({text}) { + const result = readText(text); + Scheduler.log(text); + return result; + } + function Text({text}) { Scheduler.log(text); return text; @@ -292,4 +351,91 @@ describe('useSyncExternalStore', () => { ); }, ); + + it('regression: does not infinite loop for only changing store reference in render', async () => { + let store = {value: {}}; + let listeners = []; + + const ExternalStore = { + set(value) { + // Change the store ref, but not the value. + // This will cause a new snapshot to be returned if set is called in render, + // but the value is the same. Stores should not do this, but if they do + // we shouldn't infinitely render. + store = {...store}; + setTimeout(() => { + store = {value}; + emitChange(); + }, 100); + emitChange(); + }, + subscribe(listener) { + listeners = [...listeners, listener]; + return () => { + listeners = listeners.filter(l => l !== listener); + }; + }, + getSnapshot() { + return store; + }, + }; + + function emitChange() { + listeners.forEach(l => l()); + } + + function StoreText() { + const {value} = useSyncExternalStore( + ExternalStore.subscribe, + ExternalStore.getSnapshot, + ); + + useMemo(() => { + // Set the store value on mount. + // This breaks the rules of React, but should be handled gracefully. + const newValue = {text: 'B'}; + if (value == null || newValue !== value) { + ExternalStore.set(newValue); + } + }, []); + + return ; + } + + function App() { + return ( + <> + + + + + + ); + } + + const root = ReactNoop.createRoot(); + + // The initial render suspends. + await act(async () => { + root.render(); + }); + assertLog([...(gate('enableSiblingPrerendering') ? ['(not set)'] : [])]); + + expect(root).toMatchRenderedOutput('Loading...'); + + // Resolve the data and finish rendering. + // When resolving, the store should not get stuck in an infinite loop. + await act(() => { + resolveText('A'); + }); + assertLog([ + ...(gate('enableSiblingPrerendering') + ? ['A', 'B', 'A', 'B', 'B'] + : gate(flags => flags.alwaysThrottleRetries) + ? ['A', '(not set)', 'A', '(not set)', 'B'] + : ['A', '(not set)', 'A', '(not set)', '(not set)', 'B']), + ]); + + expect(root).toMatchRenderedOutput('AB'); + }); }); From ff595de29af107255fd957ca809d3074c16bcf12 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Fri, 8 Nov 2024 16:07:37 -0800 Subject: [PATCH 362/426] [Flight] Add initial readme to react-server package (#31464) This readme documents React Server Components from `react-server` package enough to get an implementer started. It's not comprehensive but it's a beginning point and crucially adds documentation for the `prerender` API for Flight. --- packages/react-server/README.md | 248 ++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/packages/react-server/README.md b/packages/react-server/README.md index 2e5808da7581f..276a37fd5ff6c 100644 --- a/packages/react-server/README.md +++ b/packages/react-server/README.md @@ -5,3 +5,251 @@ This is an experimental package for creating custom React streaming server rende **Its API is not as stable as that of React, React Native, or React DOM, and does not follow the common versioning scheme.** **Use it at your own risk.** + +## Usage + +`react-server` is a package implementing various Server Rendering capabilities. The two implementation are codenamed `Fizz` and `Flight`. + +`Fizz` is a renderer for Server Side Rendering React. The same code that runs in the client (browser or native) is run on the server to produce an initial view to send to the client before it has to download and run React and all the user code to produce that view on the client. + +`Flight` is a renderer for React Server Components. These are components that never run on a client. The output of a React Server Component render can be a React tree that can run on the client or be SSR'd using `Fizz`. + +## `Fizz` Usage + +This part of the Readme is not fully developed yet + +## `Flight` Usage + +To use `react-server` for React Server Components you must set up an implementation package alongside `react-client`. Use an existing implementation such as `react-server-dom-webpack` as a guide. + +You might implement a render function like + +```js +import { + createRequest, + startWork, + startFlowing, + stopFlowing, + abort, +} from 'react-server/src/ReactFlightServer' + +function render( + model: ReactClientValue, + clientManifest: ClientManifest, + options?: Options, +): ReadableStream { + const request = createRequest( + model, + clientManifest, + options ? options.onError : undefined, + options ? options.identifierPrefix : undefined, + options ? options.onPostpone : undefined, + options ? options.temporaryReferences : undefined, + __DEV__ && options ? options.environmentName : undefined, + __DEV__ && options ? options.filterStackFrame : undefined, + ); + const stream = new ReadableStream( + { + type: 'bytes', + start: (controller): ?Promise => { + startWork(request); + }, + pull: (controller): ?Promise => { + startFlowing(request, controller); + }, + cancel: (reason): ?Promise => { + stopFlowing(request); + abort(request, reason); + }, + }, + {highWaterMark: 0}, + ); + return stream; +} + +``` + +### `Flight` Rendering + +`react-server` implements the React Server Components rendering implementation. React Server Components is in essence a general purpose serialization and deserialization capability with support for some built-in React primitives such as Suspense and Lazy. + +The renderable type is a superset of `structuredClone()`. In addition to all the cloneable types `react-server` can render Symbols, Promises, Iterators and Iterables, async Iterators and Iterables. + +Here are some examples of what can be rendered +```js +// primitives +createResponse(123, ...) + +// objects and Arrays +createResponse({ messages: ['hello', 'react'] }, ...) + +// Maps, Sets, and more +createResponse({ m: Map(['k', 'v'])}, ...) +``` + +Additionally React built ins can be rendered including Function Components + +Function Component are called and the return value can be any renderable type. Since `react-server` supports Promises, Function Components can be async functions. + +Here are some examples of what can be rendered +```js + +async function App({ children }) { + return children +} + +createResponse(, ...) +``` + +Finally, There are two types of references in `react-server` that can be rendered + +#### Client References +When a React Server Component framework bundles an application and encounters a `"use client"` directive it must resister exported members with `"registerClientReference"` which will encode the necessary information for `Flight` to interpret the export as a reference to be loaded on the client rather than a direct dependency on the Server module graph. + +When rendering a client reference `Flight` will encode necessary information in the serialized output to describe how to load the code which represents the client module. + +While it is common for client references to be components they can be any value. + + +```js +'use client' + +export function alert(message) { + alert(message) +} +``` + +```js +'use client' + +export function ClientComp({ onClick, message }) { + return +} +``` + +```js + +// client references don't have to just be components, anything can be +// a reference, in this case we're importing a function that will be +// passed to the ClientComp component +import { alert } from '...' +import { ClientComp } from '...' + +async function App({ children }) { + return children +} + +createResponse( + + + , +...) +``` + +#### Server References +Similarly When a React Server Component framework bundles an application and encounters a `"use server"` directive in a file or in a function body, including closures, it must implement that function as as a server entrypoint that can be called from the client. To make `Flight` aware that a function is a Server Reference the function should be registered with `registerServerReference()`. + +```js + +async function logOnServer(message) { + "use server" + console.log(message) +} + +async function App({ children }) { + // logOnServer can be used in a Server Component + logOnServer('used from server') + return children +} + +createResponse( + + + , +...) +``` + +### `Flight` Prerendering + +When rendering with `react-server` there are two broad contexts when this might happen. Realtime when responding to a user request and ahead of time when prerendering a page that can later be used more than once. + +While the core rendering implementation is the same in both cases there are subtle differences we can adopt that take advantage of the context. For instance while rendering in response to a real user request we want to stream eagerly if the consumer is requesting information. This allows us to stream content to the consumer as it becomes available but might have implications for the stability of the serialized format. When prerendering we assume there is not urgency to producing a partial result as quickly as possible so we can alter the internal implementation take advantage of this. To implement a prerender API use `createPrerenderRequest` in place of `createRequest`. + +One key semantic change prerendering has with rendering is how errors are handled. When rendering an error is embedded into the output and must be handled by the consumer such as an SSR render or on the client. However with prerendering there is an expectation that if the prerender errors then the entire prerender will be discarded or it will be used but the consumer will attempt to recover that error by asking for a dynamic render. This is analogous to how errors during SSR aren't immediately handled they are actually encoded as requests for client recovery. The error only is observed if the retry on the client actually fails. To account for this prerenders simply omit parts of the model that errored. you can use the `onError` argument in `createPrerenderRequest` to observe if an error occurred and users of your `prerender` implementation can choose whether to abandon the prerender or implement dynamic recovery when an error occurs. + +Existing implementations only return the stream containing the output of the prerender once it has completed. In the future we may introduce a `resume` API similar to the one that exists for `Fizz`. In anticipation of such an API it is expected that implementations of `prerender` return the type `Promise<{ prelude: }>` + +```js +function prerender( + model: ReactClientValue, + clientManifest: ClientManifest, + options?: Options, +): Promise { + return new Promise((resolve, reject) => { + const onFatalError = reject; + function onAllReady() { + const stream = new ReadableStream( + { + type: 'bytes', + start: (controller): ?Promise => { + startWork(request); + }, + pull: (controller): ?Promise => { + startFlowing(request, controller); + }, + cancel: (reason): ?Promise => { + stopFlowing(request); + abort(request, reason); + }, + }, + // $FlowFixMe[prop-missing] size() methods are not allowed on byte streams. + {highWaterMark: 0}, + ); + resolve({prelude: stream}); + } + const request = createPrerenderRequest( + model, + clientManifest, + onAllReady, + onFatalError, + options ? options.onError : undefined, + options ? options.identifierPrefix : undefined, + options ? options.onPostpone : undefined, + options ? options.temporaryReferences : undefined, + __DEV__ && options ? options.environmentName : undefined, + __DEV__ && options ? options.filterStackFrame : undefined, + ); + startWork(request); + }); +} +``` + +## `Flight` Reference (Incomplete) + +### `createRequest(model, bundlerConfig, ...options): Request` + +The signature of this method changes as we evolve the project so this Readme will omit the specific signature but generally this function will produce a Request that represents the rendering of some React application (the model) along with implementation specific bundler configuration. Typically this configuration will tell the `Flight` implementation how to encode Client References in the serialized output + +The `RequestInstance` represents the render. + +Rendering does not actually begin until you call `startWork` + +### `createPrerenderRequest(model, bundlerConfig, ...options): Request` + +This is similar to `createRequest` but it alters some internal semantics for how errors and aborts are treated. It returns the same type as `createRequest`. + +### `startWork(request: Request): void` + +When passed a request this will initiate the actual render. It will continue until it completes + +### `startFlowing(request: Request, destination: Destination): void` + +a destination is whatever the implementation wants to use for storing the output of the render. In existing implementations it is either a Node stream or a Web stream. When you call `startFlowing` the request will write to the destination continuously whenever more chunks are unblocked, say after an async function has resolved and there is something new to serialize. You can implement streaming backpressure using `stopFlowing()` + +### `stopFlowing(request: Request): void` + +If you need to pause or permanently end the writing of any additional serialized output for this request you can call `stopFlowing(request)`. You may start flowing again after you've stopped. This is how you would implement backpressure support for streams for instance. It's important to note that stopping flowing is not going to stop rendering it simply causes the request to buffer any serialized chunks until they are requested again with `startFlowing()`. + +### `abort(request: Request): void` + +If you want to stop rendering you can abort the request with `abort(request)`. This will cause all incomplete work to be abandoned. If the request was created with `createRequest` the abort will encode errors into any unfinished slots in the serialization. If the request was created with `createPrerenderRequest` the abort will omit anything in the places that are unfinished leaving the serialized model in an incomplete state. From 6e29479bffc188719e797801a9bf7859256b2ea0 Mon Sep 17 00:00:00 2001 From: "Henry Q. Dineen" Date: Sun, 10 Nov 2024 14:24:15 -0500 Subject: [PATCH 363/426] [devtools] allow non-coercible objects in formatConsoleArgumentsToSingleString (#31444) ## Summary We have been getting unhandled `TypeError: Cannot convert object to primitive value` errors in development that only occur when using devtools. I tracked it down to `console.error()` calls coming from Apollo Client where one of the arguments is an object without a prototype (created with `Object.create(null)`). This causes `formatConsoleArgumentsToSingleString()` in React's devtools to error as the function does not defend against `String()` throwing an error. My attempted fix is to introduce a `safeToString` function (naming suggestions appreciated) which expects `String()` to throw on certain object and in that case falls back to returning `[object Object]`, which is what `String({})` would return. ## How did you test this change? Added a new unit test. --- .../src/__tests__/utils-test.js | 6 ++++++ .../src/backend/utils/index.js | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/react-devtools-shared/src/__tests__/utils-test.js b/packages/react-devtools-shared/src/__tests__/utils-test.js index f35cacc73308f..94726312c3bfa 100644 --- a/packages/react-devtools-shared/src/__tests__/utils-test.js +++ b/packages/react-devtools-shared/src/__tests__/utils-test.js @@ -155,6 +155,12 @@ describe('utils', () => { 'Symbol(abc) 123', ); }); + + it('should gracefully handle objects with no prototype', () => { + expect( + formatConsoleArgumentsToSingleString('%o', Object.create(null)), + ).toEqual('%o [object Object]'); + }); }); describe('formatWithStyles', () => { diff --git a/packages/react-devtools-shared/src/backend/utils/index.js b/packages/react-devtools-shared/src/backend/utils/index.js index c07536e422608..977683ef9a208 100644 --- a/packages/react-devtools-shared/src/backend/utils/index.js +++ b/packages/react-devtools-shared/src/backend/utils/index.js @@ -167,6 +167,19 @@ export function serializeToString(data: any): string { ); } +function safeToString(val: any): string { + try { + return String(val); + } catch (err) { + if (typeof val === 'object') { + // An object with no prototype and no `[Symbol.toPrimitive]()`, `toString()`, and `valueOf()` methods would throw. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion + return '[object Object]'; + } + throw err; + } +} + // based on https://github.com/tmpfs/format-util/blob/0e62d430efb0a1c51448709abd3e2406c14d8401/format.js#L1 // based on https://developer.mozilla.org/en-US/docs/Web/API/console#Using_string_substitutions // Implements s, d, i and f placeholders @@ -176,7 +189,7 @@ export function formatConsoleArgumentsToSingleString( ): string { const args = inputArgs.slice(); - let formatted: string = String(maybeMessage); + let formatted: string = safeToString(maybeMessage); // If the first argument is a string, check for substitutions. if (typeof maybeMessage === 'string') { @@ -211,7 +224,7 @@ export function formatConsoleArgumentsToSingleString( // Arguments that remain after formatting. if (args.length) { for (let i = 0; i < args.length; i++) { - formatted += ' ' + String(args[i]); + formatted += ' ' + safeToString(args[i]); } } From ed15d5007ca7ee4d61294c741ce3e858d3c1d461 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Sun, 10 Nov 2024 11:58:52 -0800 Subject: [PATCH 364/426] update flight readme wording (#31466) --- packages/react-server/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-server/README.md b/packages/react-server/README.md index 276a37fd5ff6c..60637bbff682f 100644 --- a/packages/react-server/README.md +++ b/packages/react-server/README.md @@ -248,7 +248,7 @@ a destination is whatever the implementation wants to use for storing the output ### `stopFlowing(request: Request): void` -If you need to pause or permanently end the writing of any additional serialized output for this request you can call `stopFlowing(request)`. You may start flowing again after you've stopped. This is how you would implement backpressure support for streams for instance. It's important to note that stopping flowing is not going to stop rendering it simply causes the request to buffer any serialized chunks until they are requested again with `startFlowing()`. +If you need to pause or permanently end the writing of any additional serialized output for this request you can call `stopFlowing(request)`. You may start flowing again after you've stopped. This is how you would implement backpressure support for streams for instance. It's important to note that stopping flowing is not going to stop rendering. If you want rendering to stop you must `abort` the request. ### `abort(request: Request): void` From b836de613d66ff36574af95cb93ad15fd743d1f4 Mon Sep 17 00:00:00 2001 From: Ricky Date: Mon, 11 Nov 2024 17:25:37 -0500 Subject: [PATCH 365/426] Fix continuation bug (#31434) ## Overview In `scheduleTaskForRootDuringMicrotask` we clear `root.callbackNode` if the work loop is [suspended waiting on data](https://github.com/facebook/react/blob/ac3ca097aeecae8fe3ec7f9b286307a923676518/packages/react-reconciler/src/ReactFiberRootScheduler.js#L338). But we don't null check `root.callbackNode` before returning a continuation in `performWorkOnRootViaSchedulerTask` where `scheduleTaskForRootDuringMicrotask` is synchronously called, causing an infinite loop when the only thing in the queue is something suspended waiting on data. This essentially restores the behavior from here: https://github.com/facebook/react/pull/26328/files#diff-72ff2175ae3569037f0b16802a41b0cda2b2d66bb97f2bda78ed8445ed487b58L1168 Found by investigating the failures for https://github.com/facebook/react/pull/31417 ## TODO - add a test --------- Co-authored-by: Joe Savona --- .../src/ReactFiberRootScheduler.js | 2 +- .../__tests__/ActivityLegacySuspense-test.js | 604 ++++++++++++++++++ .../src/__tests__/ActivitySuspense-test.js | 94 ++- 3 files changed, 681 insertions(+), 19 deletions(-) create mode 100644 packages/react-reconciler/src/__tests__/ActivityLegacySuspense-test.js diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 39f6f466ed983..1f529d9e4df31 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -482,7 +482,7 @@ function performWorkOnRootViaSchedulerTask( // only safe to do because we know we're at the end of the browser task. // So although it's not an actual microtask, it might as well be. scheduleTaskForRootDuringMicrotask(root, now()); - if (root.callbackNode === originalCallbackNode) { + if (root.callbackNode != null && root.callbackNode === originalCallbackNode) { // The task node scheduled for this root is the same one that's // currently executed. Need to return a continuation. return performWorkOnRootViaSchedulerTask.bind(null, root); diff --git a/packages/react-reconciler/src/__tests__/ActivityLegacySuspense-test.js b/packages/react-reconciler/src/__tests__/ActivityLegacySuspense-test.js new file mode 100644 index 0000000000000..424594cc35e80 --- /dev/null +++ b/packages/react-reconciler/src/__tests__/ActivityLegacySuspense-test.js @@ -0,0 +1,604 @@ +let React; +let ReactNoop; +let Scheduler; +let act; +let LegacyHidden; +let Activity; +let Suspense; +let useState; +let useEffect; +let startTransition; +let textCache; +let waitFor; +let waitForPaint; +let assertLog; + +describe('Activity Suspense', () => { + beforeEach(() => { + jest.resetModules(); + + React = require('react'); + ReactNoop = require('react-noop-renderer'); + Scheduler = require('scheduler'); + act = require('internal-test-utils').act; + LegacyHidden = React.unstable_LegacyHidden; + Activity = React.unstable_Activity; + Suspense = React.Suspense; + useState = React.useState; + useEffect = React.useEffect; + startTransition = React.startTransition; + + const InternalTestUtils = require('internal-test-utils'); + waitFor = InternalTestUtils.waitFor; + waitForPaint = InternalTestUtils.waitForPaint; + assertLog = InternalTestUtils.assertLog; + + textCache = new Map(); + }); + + function resolveText(text) { + const record = textCache.get(text); + if (record === undefined) { + const newRecord = { + status: 'resolved', + value: text, + }; + textCache.set(text, newRecord); + } else if (record.status === 'pending') { + const thenable = record.value; + record.status = 'resolved'; + record.value = text; + thenable.pings.forEach(t => t()); + } + } + + function readText(text) { + const record = textCache.get(text); + if (record !== undefined) { + switch (record.status) { + case 'pending': + Scheduler.log(`Suspend! [${text}]`); + throw record.value; + case 'rejected': + throw record.value; + case 'resolved': + return record.value; + } + } else { + Scheduler.log(`Suspend! [${text}]`); + const thenable = { + pings: [], + then(resolve) { + if (newRecord.status === 'pending') { + thenable.pings.push(resolve); + } else { + Promise.resolve().then(() => resolve(newRecord.value)); + } + }, + }; + + const newRecord = { + status: 'pending', + value: thenable, + }; + textCache.set(text, newRecord); + + throw thenable; + } + } + + function Text({text}) { + Scheduler.log(text); + return text; + } + + function AsyncText({text}) { + readText(text); + Scheduler.log(text); + return text; + } + + // @gate enableActivity + it('basic example of suspending inside hidden tree', async () => { + const root = ReactNoop.createRoot(); + + function App() { + return ( + }> + + + + + + + + + + ); + } + + // The hidden tree hasn't finished loading, but we should still be able to + // show the surrounding contents. The outer Suspense boundary + // isn't affected. + await act(() => { + root.render(); + }); + assertLog(['Visible', 'Suspend! [Hidden]']); + expect(root).toMatchRenderedOutput(Visible); + + // When the data resolves, we should be able to finish prerendering + // the hidden tree. + await act(async () => { + await resolveText('Hidden'); + }); + assertLog(['Hidden']); + expect(root).toMatchRenderedOutput( + <> + Visible + + , + ); + }); + + // @gate enableLegacyHidden + test('LegacyHidden does not handle suspense', async () => { + const root = ReactNoop.createRoot(); + + function App() { + return ( + }> + + + + + + + + + + ); + } + + // Unlike Activity, LegacyHidden never captures if something suspends + await act(() => { + root.render(); + }); + assertLog(['Visible', 'Suspend! [Hidden]', 'Loading...']); + // Nearest Suspense boundary switches to a fallback even though the + // suspended content is hidden. + expect(root).toMatchRenderedOutput( + <> + + Loading... + , + ); + }); + + // @gate __DEV__ && enableActivity + test('Regression: Suspending on hide should not infinite loop.', async () => { + // This regression only repros in public act. + global.IS_REACT_ACT_ENVIRONMENT = true; + const root = ReactNoop.createRoot(); + + let setMode; + function Container({text}) { + const [mode, _setMode] = React.useState('visible'); + setMode = _setMode; + useEffect(() => { + return () => { + Scheduler.log(`Clear [${text}]`); + textCache.delete(text); + }; + }); + return ( + //$FlowFixMe + + + + + + ); + } + + await React.act(() => { + root.render(); + }); + assertLog([ + 'Suspend! [hello]', + ...(gate(flags => flags.enableSiblingPrerendering) + ? ['Suspend! [hello]'] + : []), + ]); + expect(root).toMatchRenderedOutput('Loading'); + + await React.act(async () => { + await resolveText('hello'); + }); + assertLog(['hello']); + expect(root).toMatchRenderedOutput('hello'); + + await React.act(async () => { + setMode('hidden'); + }); + assertLog(['Clear [hello]', 'Suspend! [hello]']); + expect(root).toMatchRenderedOutput(''); + }); + + // @gate enableActivity + test("suspending inside currently hidden tree that's switching to visible", async () => { + const root = ReactNoop.createRoot(); + + function Details({open, children}) { + return ( + }> + + + + + {children} + + + ); + } + + // The hidden tree hasn't finished loading, but we should still be able to + // show the surrounding contents. It doesn't matter that there's no + // Suspense boundary because the unfinished content isn't visible. + await act(() => { + root.render( +
+ +
, + ); + }); + assertLog(['Closed', 'Suspend! [Async]']); + expect(root).toMatchRenderedOutput(Closed); + + // But when we switch the boundary from hidden to visible, it should + // now bubble to the nearest Suspense boundary. + await act(() => { + startTransition(() => { + root.render( +
+ +
, + ); + }); + }); + assertLog(['Open', 'Suspend! [Async]', 'Loading...']); + // It should suspend with delay to prevent the already-visible Suspense + // boundary from switching to a fallback + expect(root).toMatchRenderedOutput(Closed); + + // Resolve the data and finish rendering + await act(async () => { + await resolveText('Async'); + }); + assertLog(['Open', 'Async']); + expect(root).toMatchRenderedOutput( + <> + Open + Async + , + ); + }); + + // @gate enableActivity + test("suspending inside currently visible tree that's switching to hidden", async () => { + const root = ReactNoop.createRoot(); + + function Details({open, children}) { + return ( + }> + + + + + {children} + + + ); + } + + // Initial mount. Nothing suspends + await act(() => { + root.render( +
+ +
, + ); + }); + assertLog(['Open', '(empty)']); + expect(root).toMatchRenderedOutput( + <> + Open + (empty) + , + ); + + // Update that suspends inside the currently visible tree + await act(() => { + startTransition(() => { + root.render( +
+ +
, + ); + }); + }); + assertLog(['Open', 'Suspend! [Async]', 'Loading...']); + // It should suspend with delay to prevent the already-visible Suspense + // boundary from switching to a fallback + expect(root).toMatchRenderedOutput( + <> + Open + (empty) + , + ); + + // Update that hides the suspended tree + await act(() => { + startTransition(() => { + root.render( +
+ +
, + ); + }); + }); + // Now the visible part of the tree can commit without being blocked + // by the suspended content, which is hidden. + assertLog(['Closed', 'Suspend! [Async]']); + expect(root).toMatchRenderedOutput( + <> + Closed + + , + ); + + // Resolve the data and finish rendering + await act(async () => { + await resolveText('Async'); + }); + assertLog(['Async']); + expect(root).toMatchRenderedOutput( + <> + Closed + + , + ); + }); + + // @gate enableActivity + test('update that suspends inside hidden tree', async () => { + let setText; + function Child() { + const [text, _setText] = useState('A'); + setText = _setText; + return ; + } + + function App({show}) { + return ( + + + + + + ); + } + + const root = ReactNoop.createRoot(); + resolveText('A'); + await act(() => { + root.render(); + }); + assertLog(['A']); + + await act(() => { + startTransition(() => { + setText('B'); + }); + }); + }); + + // @gate enableActivity + test('updates at multiple priorities that suspend inside hidden tree', async () => { + let setText; + let setStep; + function Child() { + const [text, _setText] = useState('A'); + setText = _setText; + + const [step, _setStep] = useState(0); + setStep = _setStep; + + return ; + } + + function App({show}) { + return ( + + + + + + ); + } + + const root = ReactNoop.createRoot(); + resolveText('A0'); + await act(() => { + root.render(); + }); + assertLog(['A0']); + expect(root).toMatchRenderedOutput(); + + await act(() => { + React.startTransition(() => { + setStep(1); + }); + ReactNoop.flushSync(() => { + setText('B'); + }); + }); + assertLog([ + // The high priority render suspends again + 'Suspend! [B0]', + // There's still pending work in another lane, so we should attempt + // that, too. + 'Suspend! [B1]', + ]); + expect(root).toMatchRenderedOutput(); + + // Resolve the data and finish rendering + await act(() => { + resolveText('B1'); + }); + assertLog(['B1']); + expect(root).toMatchRenderedOutput(); + }); + + // @gate enableActivity + test('detect updates to a hidden tree during a concurrent event', async () => { + // This is a pretty complex test case. It relates to how we detect if an + // update is made to a hidden tree: when scheduling the update, we walk up + // the fiber return path to see if any of the parents is a hidden Activity + // component. This doesn't work if there's already a render in progress, + // because the tree might be about to flip to hidden. To avoid a data race, + // queue updates atomically: wait to queue the update until after the + // current render has finished. + + let setInner; + function Child({outer}) { + const [inner, _setInner] = useState(0); + setInner = _setInner; + + useEffect(() => { + // Inner and outer values are always updated simultaneously, so they + // should always be consistent. + if (inner !== outer) { + Scheduler.log('Tearing! Inner and outer are inconsistent!'); + } else { + Scheduler.log('Inner and outer are consistent'); + } + }, [inner, outer]); + + return ; + } + + let setOuter; + function App({show}) { + const [outer, _setOuter] = useState(0); + setOuter = _setOuter; + return ( + <> + + + + + + + + + }> + + + + + + ); + } + + // Render a hidden tree + const root = ReactNoop.createRoot(); + resolveText('Async: 0'); + await act(() => { + root.render(); + }); + assertLog([ + 'Inner: 0', + 'Outer: 0', + 'Sibling: 0', + 'Inner and outer are consistent', + ]); + expect(root).toMatchRenderedOutput( + <> + Inner: 0 + Outer: 0 + Sibling: 0 + , + ); + + await act(async () => { + // Update a value both inside and outside the hidden tree. These values + // must always be consistent. + startTransition(() => { + setOuter(1); + setInner(1); + // In the same render, also hide the offscreen tree. + root.render(); + }); + + await waitFor([ + // The outer update will commit, but the inner update is deferred until + // a later render. + 'Outer: 1', + ]); + + // Assert that we haven't committed quite yet + expect(root).toMatchRenderedOutput( + <> + Inner: 0 + Outer: 0 + Sibling: 0 + , + ); + + // Before the tree commits, schedule a concurrent event. The inner update + // is to a tree that's just about to be hidden. + startTransition(() => { + setOuter(2); + setInner(2); + }); + + // Finish rendering and commit the in-progress render. + await waitForPaint(['Sibling: 1']); + expect(root).toMatchRenderedOutput( + <> + + Outer: 1 + Sibling: 1 + , + ); + + // Now reveal the hidden tree at high priority. + ReactNoop.flushSync(() => { + root.render(); + }); + assertLog([ + // There are two pending updates on Inner, but only the first one + // is processed, even though they share the same lane. If the second + // update were erroneously processed, then Inner would be inconsistent + // with Outer. + 'Inner: 1', + 'Outer: 1', + 'Sibling: 1', + 'Inner and outer are consistent', + ]); + }); + assertLog([ + 'Inner: 2', + 'Outer: 2', + 'Sibling: 2', + 'Inner and outer are consistent', + ]); + expect(root).toMatchRenderedOutput( + <> + Inner: 2 + Outer: 2 + Sibling: 2 + , + ); + }); +}); diff --git a/packages/react-reconciler/src/__tests__/ActivitySuspense-test.js b/packages/react-reconciler/src/__tests__/ActivitySuspense-test.js index d02ae70e523ca..2fb35df4574ad 100644 --- a/packages/react-reconciler/src/__tests__/ActivitySuspense-test.js +++ b/packages/react-reconciler/src/__tests__/ActivitySuspense-test.js @@ -12,6 +12,7 @@ let textCache; let waitFor; let waitForPaint; let assertLog; +let use; describe('Activity Suspense', () => { beforeEach(() => { @@ -27,6 +28,7 @@ describe('Activity Suspense', () => { useState = React.useState; useEffect = React.useEffect; startTransition = React.startTransition; + use = React.use; const InternalTestUtils = require('internal-test-utils'); waitFor = InternalTestUtils.waitFor; @@ -45,10 +47,10 @@ describe('Activity Suspense', () => { }; textCache.set(text, newRecord); } else if (record.status === 'pending') { - const thenable = record.value; + const resolve = record.resolve; record.status = 'resolved'; record.value = text; - thenable.pings.forEach(t => t()); + resolve(); } } @@ -58,7 +60,7 @@ describe('Activity Suspense', () => { switch (record.status) { case 'pending': Scheduler.log(`Suspend! [${text}]`); - throw record.value; + return use(record.value); case 'rejected': throw record.value; case 'resolved': @@ -66,24 +68,19 @@ describe('Activity Suspense', () => { } } else { Scheduler.log(`Suspend! [${text}]`); - const thenable = { - pings: [], - then(resolve) { - if (newRecord.status === 'pending') { - thenable.pings.push(resolve); - } else { - Promise.resolve().then(() => resolve(newRecord.value)); - } - }, - }; + let resolve; + const promise = new Promise(_resolve => { + resolve = _resolve; + }); const newRecord = { status: 'pending', - value: thenable, + value: promise, + resolve, }; textCache.set(text, newRecord); - throw thenable; + return use(promise); } } @@ -174,6 +171,56 @@ describe('Activity Suspense', () => { ); }); + // @gate __DEV__ && enableActivity + test('Regression: Suspending on hide should not infinite loop.', async () => { + // This regression only repros in public act. + global.IS_REACT_ACT_ENVIRONMENT = true; + const root = ReactNoop.createRoot(); + + let setMode; + function Container({text}) { + const [mode, _setMode] = React.useState('visible'); + setMode = _setMode; + useEffect(() => { + return () => { + Scheduler.log(`Clear [${text}]`); + textCache.delete(text); + }; + }); + return ( + //$FlowFixMe + + + + + + ); + } + + await React.act(() => { + root.render(); + }); + assertLog([ + 'Suspend! [hello]', + ...(gate(flags => flags.enableSiblingPrerendering) + ? ['Suspend! [hello]'] + : []), + ]); + expect(root).toMatchRenderedOutput('Loading'); + + await React.act(async () => { + await resolveText('hello'); + }); + assertLog(['hello']); + expect(root).toMatchRenderedOutput('hello'); + + await React.act(() => { + setMode('hidden'); + }); + assertLog(['Clear [hello]', 'Suspend! [hello]']); + expect(root).toMatchRenderedOutput(''); + }); + // @gate enableActivity test("suspending inside currently hidden tree that's switching to visible", async () => { const root = ReactNoop.createRoot(); @@ -215,7 +262,11 @@ describe('Activity Suspense', () => { ); }); }); - assertLog(['Open', 'Suspend! [Async]', 'Loading...']); + assertLog([ + 'Open', + 'Suspend! [Async]', + ...(gate(flags => flags.enableSiblingPrerendering) ? ['Loading...'] : []), + ]); // It should suspend with delay to prevent the already-visible Suspense // boundary from switching to a fallback expect(root).toMatchRenderedOutput(Closed); @@ -224,7 +275,10 @@ describe('Activity Suspense', () => { await act(async () => { await resolveText('Async'); }); - assertLog(['Open', 'Async']); + assertLog([ + ...(gate(flags => flags.enableSiblingPrerendering) ? ['Open'] : []), + 'Async', + ]); expect(root).toMatchRenderedOutput( <> Open @@ -276,7 +330,11 @@ describe('Activity Suspense', () => { ); }); }); - assertLog(['Open', 'Suspend! [Async]', 'Loading...']); + assertLog([ + 'Open', + 'Suspend! [Async]', + ...(gate(flags => flags.enableSiblingPrerendering) ? ['Loading...'] : []), + ]); // It should suspend with delay to prevent the already-visible Suspense // boundary from switching to a fallback expect(root).toMatchRenderedOutput( From 2ec26bc4323673d1f2035191d3aaf0a18b20d488 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:04:29 -0500 Subject: [PATCH 366/426] [compiler] Repro for mutable range edge case (#31479) See test fixtures --- ...g-aliased-capture-aliased-mutate.expect.md | 107 ++++++++++++++++++ .../bug-aliased-capture-aliased-mutate.js | 53 +++++++++ .../bug-aliased-capture-mutate.expect.md | 87 ++++++++++++++ .../compiler/bug-aliased-capture-mutate.js | 34 ++++++ .../packages/snap/src/SproutTodoFilter.ts | 2 + 5 files changed, 283 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.js create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.js diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.expect.md new file mode 100644 index 0000000000000..d0ad9e2f9dbe5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.expect.md @@ -0,0 +1,107 @@ + +## Input + +```javascript +// @flow @enableTransitivelyFreezeFunctionExpressions:false +import {arrayPush, setPropertyByKey, Stringify} from 'shared-runtime'; + +/** + * 1. `InferMutableRanges` derives the mutable range of identifiers and their + * aliases from `LoadLocal`, `PropertyLoad`, etc + * - After this pass, y's mutable range only extends to `arrayPush(x, y)` + * - We avoid assigning mutable ranges to loads after y's mutable range, as + * these are working with an immutable value. As a result, `LoadLocal y` and + * `PropertyLoad y` do not get mutable ranges + * 2. `InferReactiveScopeVariables` extends mutable ranges and creates scopes, + * as according to the 'co-mutation' of different values + * - Here, we infer that + * - `arrayPush(y, x)` might alias `x` and `y` to each other + * - `setPropertyKey(x, ...)` may mutate both `x` and `y` + * - This pass correctly extends the mutable range of `y` + * - Since we didn't run `InferMutableRange` logic again, the LoadLocal / + * PropertyLoads still don't have a mutable range + * + * Note that the this bug is an edge case. Compiler output is only invalid for: + * - function expressions with + * `enableTransitivelyFreezeFunctionExpressions:false` + * - functions that throw and get retried without clearing the memocache + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":11},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}
+ */ +function useFoo({a, b}: {a: number, b: number}) { + const x = []; + const y = {value: a}; + + arrayPush(x, y); // x and y co-mutate + const y_alias = y; + const cb = () => y_alias.value; + setPropertyByKey(x[0], 'value', b); // might overwrite y.value + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: 2, b: 10}], + sequentialRenders: [ + {a: 2, b: 10}, + {a: 2, b: 11}, + ], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { arrayPush, setPropertyByKey, Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(5); + const { a, b } = t0; + let t1; + if ($[0] !== a || $[1] !== b) { + const x = []; + const y = { value: a }; + + arrayPush(x, y); + const y_alias = y; + let t2; + if ($[3] !== y_alias.value) { + t2 = () => y_alias.value; + $[3] = y_alias.value; + $[4] = t2; + } else { + t2 = $[4]; + } + const cb = t2; + setPropertyByKey(x[0], "value", b); + t1 = ; + $[0] = a; + $[1] = b; + $[2] = t1; + } else { + t1 = $[2]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: 2, b: 10 }], + sequentialRenders: [ + { a: 2, b: 10 }, + { a: 2, b: 11 }, + ], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.js new file mode 100644 index 0000000000000..c46ecd6250b42 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-aliased-mutate.js @@ -0,0 +1,53 @@ +// @flow @enableTransitivelyFreezeFunctionExpressions:false +import {arrayPush, setPropertyByKey, Stringify} from 'shared-runtime'; + +/** + * 1. `InferMutableRanges` derives the mutable range of identifiers and their + * aliases from `LoadLocal`, `PropertyLoad`, etc + * - After this pass, y's mutable range only extends to `arrayPush(x, y)` + * - We avoid assigning mutable ranges to loads after y's mutable range, as + * these are working with an immutable value. As a result, `LoadLocal y` and + * `PropertyLoad y` do not get mutable ranges + * 2. `InferReactiveScopeVariables` extends mutable ranges and creates scopes, + * as according to the 'co-mutation' of different values + * - Here, we infer that + * - `arrayPush(y, x)` might alias `x` and `y` to each other + * - `setPropertyKey(x, ...)` may mutate both `x` and `y` + * - This pass correctly extends the mutable range of `y` + * - Since we didn't run `InferMutableRange` logic again, the LoadLocal / + * PropertyLoads still don't have a mutable range + * + * Note that the this bug is an edge case. Compiler output is only invalid for: + * - function expressions with + * `enableTransitivelyFreezeFunctionExpressions:false` + * - functions that throw and get retried without clearing the memocache + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":11},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":10},"shouldInvokeFns":true}
+ */ +function useFoo({a, b}: {a: number, b: number}) { + const x = []; + const y = {value: a}; + + arrayPush(x, y); // x and y co-mutate + const y_alias = y; + const cb = () => y_alias.value; + setPropertyByKey(x[0], 'value', b); // might overwrite y.value + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: 2, b: 10}], + sequentialRenders: [ + {a: 2, b: 10}, + {a: 2, b: 11}, + ], +}; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.expect.md new file mode 100644 index 0000000000000..c35efe6a16bb5 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.expect.md @@ -0,0 +1,87 @@ + +## Input + +```javascript +// @flow @enableTransitivelyFreezeFunctionExpressions:false +import {setPropertyByKey, Stringify} from 'shared-runtime'; + +/** + * Variation of bug in `bug-aliased-capture-aliased-mutate` + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":3},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ */ + +function useFoo({a}: {a: number, b: number}) { + const arr = []; + const obj = {value: a}; + + setPropertyByKey(obj, 'arr', arr); + const obj_alias = obj; + const cb = () => obj_alias.arr.length; + for (let i = 0; i < a; i++) { + arr.push(i); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: 2}], + sequentialRenders: [{a: 2}, {a: 3}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { setPropertyByKey, Stringify } from "shared-runtime"; + +function useFoo(t0) { + const $ = _c(4); + const { a } = t0; + let t1; + if ($[0] !== a) { + const arr = []; + const obj = { value: a }; + + setPropertyByKey(obj, "arr", arr); + const obj_alias = obj; + let t2; + if ($[2] !== obj_alias.arr.length) { + t2 = () => obj_alias.arr.length; + $[2] = obj_alias.arr.length; + $[3] = t2; + } else { + t2 = $[3]; + } + const cb = t2; + for (let i = 0; i < a; i++) { + arr.push(i); + } + + t1 = ; + $[0] = a; + $[1] = t1; + } else { + t1 = $[1]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{ a: 2 }], + sequentialRenders: [{ a: 2 }, { a: 3 }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.js new file mode 100644 index 0000000000000..a7e57672665f6 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-aliased-capture-mutate.js @@ -0,0 +1,34 @@ +// @flow @enableTransitivelyFreezeFunctionExpressions:false +import {setPropertyByKey, Stringify} from 'shared-runtime'; + +/** + * Variation of bug in `bug-aliased-capture-aliased-mutate` + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":3},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ */ + +function useFoo({a}: {a: number, b: number}) { + const arr = []; + const obj = {value: a}; + + setPropertyByKey(obj, 'arr', arr); + const obj_alias = obj; + const cb = () => obj_alias.arr.length; + for (let i = 0; i < a; i++) { + arr.push(i); + } + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: useFoo, + params: [{a: 2}], + sequentialRenders: [{a: 2}, {a: 3}], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index b868afc52b82d..1971fe0d33161 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -480,6 +480,8 @@ const skipFilter = new Set([ 'fbt/bug-fbt-plural-multiple-mixed-call-tag', 'bug-object-expression-computed-key-modified-during-after-construction-hoisted-sequence-expr', 'bug-invalid-hoisting-functionexpr', + 'bug-aliased-capture-aliased-mutate', + 'bug-aliased-capture-mutate', 'bug-functiondecl-hoisting', 'bug-try-catch-maybe-null-dependency', 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted', From d9b3841ca64f292e3450edcd0a87eca05ac4c5f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Tue, 12 Nov 2024 12:46:55 -0500 Subject: [PATCH 367/426] Revert "Performance tracks are sorted by start time" hack (#31518) This reverts commit d3bf32a95806b6d583ef041b8d83781cd686cfd8 which was part of #30983 When you have very deep trees this trick can cause the top levels to skew way too much from the real numbers. Creating unbalanced trees. The bug should have been fixed in Chrome Canary now so that entries added later are sorted to go first which should've addressed this issue. --- packages/react-reconciler/src/ReactProfilerTimer.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index 0df3427fe86b2..e59b5cb8e56ed 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -193,13 +193,8 @@ export function popComponentEffectStart(prevEffectStart: number): void { if (!enableProfilerTimer || !enableProfilerCommitHooks) { return; } - if (prevEffectStart < 0) { - // If the parent component didn't have a start time, we use the start - // of the child as the parent's start time. We subtrack a minimal amount of - // time to ensure that the parent's start time is before the child to ensure - // that the performance tracks line up in the right order. - componentEffectStartTime -= 0.001; - } else { + // If the parent component didn't have a start time, we let this current time persist. + if (prevEffectStart >= 0) { // Otherwise, we restore the previous parent's start time. componentEffectStartTime = prevEffectStart; } From 3770c11011c78d227c7013468787e0c34ae91dc8 Mon Sep 17 00:00:00 2001 From: mofeiZ <34200447+mofeiZ@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:04:54 -0500 Subject: [PATCH 368/426] [compiler] repro for reactive ref.current accesses (#31519) See test fixture --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31519). * #31521 * __->__ #31519 --- .../compiler/bug-nonreactive-ref.expect.md | 89 +++++++++++++++++++ .../fixtures/compiler/bug-nonreactive-ref.tsx | 33 +++++++ .../packages/snap/src/SproutTodoFilter.ts | 1 + 3 files changed, 123 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.expect.md create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.tsx diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.expect.md new file mode 100644 index 0000000000000..f79df15d52492 --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.expect.md @@ -0,0 +1,89 @@ + +## Input + +```javascript +import {useRef} from 'react'; +import {Stringify} from 'shared-runtime'; + +/** + * Bug: we're currently filtering out `ref.current` dependencies in + * `propagateScopeDependencies:checkValidDependency`. This is incorrect. + * Instead, we should always take a dependency on ref values (the outer box) as + * they may be reactive. Pruning should be done in + * `pruneNonReactiveDependencies` + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ */ +function Component({cond}) { + const ref1 = useRef(1); + const ref2 = useRef(2); + const ref = cond ? ref1 : ref2; + const cb = () => ref.current; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true}], + sequentialRenders: [{cond: true}, {cond: false}], +}; + +``` + +## Code + +```javascript +import { c as _c } from "react/compiler-runtime"; +import { useRef } from "react"; +import { Stringify } from "shared-runtime"; + +/** + * Bug: we're currently filtering out `ref.current` dependencies in + * `propagateScopeDependencies:checkValidDependency`. This is incorrect. + * Instead, we should always take a dependency on ref values (the outer box) as + * they may be reactive. Pruning should be done in + * `pruneNonReactiveDependencies` + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ */ +function Component(t0) { + const $ = _c(1); + const { cond } = t0; + const ref1 = useRef(1); + const ref2 = useRef(2); + const ref = cond ? ref1 : ref2; + let t1; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + const cb = () => ref.current; + t1 = ; + $[0] = t1; + } else { + t1 = $[0]; + } + return t1; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ cond: true }], + sequentialRenders: [{ cond: true }, { cond: false }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.tsx b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.tsx new file mode 100644 index 0000000000000..a0115f2df3cfb --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/bug-nonreactive-ref.tsx @@ -0,0 +1,33 @@ +import {useRef} from 'react'; +import {Stringify} from 'shared-runtime'; + +/** + * Bug: we're currently filtering out `ref.current` dependencies in + * `propagateScopeDependencies:checkValidDependency`. This is incorrect. + * Instead, we should always take a dependency on ref values (the outer box) as + * they may be reactive. Pruning should be done in + * `pruneNonReactiveDependencies` + * + * Found differences in evaluator results + * Non-forget (expected): + * (kind: ok) + *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":2},"shouldInvokeFns":true}
+ * Forget: + * (kind: ok) + *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ *
{"cb":{"kind":"Function","result":1},"shouldInvokeFns":true}
+ */ +function Component({cond}) { + const ref1 = useRef(1); + const ref2 = useRef(2); + const ref = cond ? ref1 : ref2; + const cb = () => ref.current; + return ; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{cond: true}], + sequentialRenders: [{cond: true}, {cond: false}], +}; diff --git a/compiler/packages/snap/src/SproutTodoFilter.ts b/compiler/packages/snap/src/SproutTodoFilter.ts index 1971fe0d33161..6c136f6310928 100644 --- a/compiler/packages/snap/src/SproutTodoFilter.ts +++ b/compiler/packages/snap/src/SproutTodoFilter.ts @@ -484,6 +484,7 @@ const skipFilter = new Set([ 'bug-aliased-capture-mutate', 'bug-functiondecl-hoisting', 'bug-try-catch-maybe-null-dependency', + 'bug-nonreactive-ref', 'reduce-reactive-deps/bug-infer-function-cond-access-not-hoisted', 'bug-invalid-phi-as-dependency', 'reduce-reactive-deps/bug-merge-uncond-optional-chain-and-cond', From 7ac8e612118a1285ac6aa0bb333d910b9f23a7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 13 Nov 2024 10:57:15 -0500 Subject: [PATCH 369/426] Only log component level profiling for components that actually performed work (#31522) This provides less context but skips a lot of noise. Previously we were including parent components to provide context about what is rendering but this turns out to be: 1) Very expensive due to the overhead of `performance.measure()` while profiling. 2) Unactionable noise in the profile that hurt more than it added in real apps with large trees. This approach instead just add performance.measure calls for each component that was marked as PerformedWork (which was used for this purpose by React Profiler) or had any Effects. Not everything gets marked with PerformedWork though. E.g. DOM nodes do not but they can have significant render times since creating them takes time. We might consider including them if a self-time threshold is met. Because there is little to no context about the component anymore it becomes really essential to get a feature from Chrome DevTools that can link to something with more context like React DevTools. --- .../react-reconciler/src/ReactFiberCommitWork.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 9384f5cbd574b..5c64a0407048e 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -97,6 +97,7 @@ import { MaySuspendCommit, FormReset, Cloned, + PerformedWork, } from './ReactFiberFlags'; import { commitStartTime, @@ -602,7 +603,8 @@ function commitLayoutEffectOnFiber( enableComponentPerformanceTrack && (finishedWork.mode & ProfileMode) !== NoMode && componentEffectStartTime >= 0 && - componentEffectEndTime >= 0 + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 ) { logComponentEffect( finishedWork, @@ -2106,7 +2108,8 @@ function commitMutationEffectsOnFiber( enableComponentPerformanceTrack && (finishedWork.mode & ProfileMode) !== NoMode && componentEffectStartTime >= 0 && - componentEffectEndTime >= 0 + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 ) { logComponentEffect( finishedWork, @@ -2647,7 +2650,8 @@ function commitPassiveMountOnFiber( enableProfilerTimer && enableComponentPerformanceTrack && (finishedWork.mode & ProfileMode) !== NoMode && - ((finishedWork.actualStartTime: any): number) > 0 + ((finishedWork.actualStartTime: any): number) > 0 && + (finishedWork.flags & PerformedWork) !== NoFlags ) { logComponentRender( finishedWork, @@ -2929,7 +2933,8 @@ function commitPassiveMountOnFiber( enableComponentPerformanceTrack && (finishedWork.mode & ProfileMode) !== NoMode && componentEffectStartTime >= 0 && - componentEffectEndTime >= 0 + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 ) { logComponentEffect( finishedWork, @@ -3448,7 +3453,8 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void { enableComponentPerformanceTrack && (finishedWork.mode & ProfileMode) !== NoMode && componentEffectStartTime >= 0 && - componentEffectEndTime >= 0 + componentEffectEndTime >= 0 && + componentEffectDuration > 0.05 ) { logComponentEffect( finishedWork, From 380f5d675d2269f090d15c3f92e10de66e12516c Mon Sep 17 00:00:00 2001 From: lauren Date: Wed, 13 Nov 2024 15:13:46 -0500 Subject: [PATCH 370/426] Fix sizebot (#31535) Our CI workflows generally cache `**/node_modules` (note the glob, it caches all transitive node_module directories) to speed up startup for new jobs that don't change any dependencies. However it seems like one of our caches got into a weird state (not sure how it happened) where the `build` directory (used in various other scripts as the directory for compiled React packages) would contain a `node_modules` directory as well. This made sizebot size change messages very big since it would try to compare every single file in `build/node_modules`. The fix is to ensure we always clean the `build` directory before doing anything with it. We can also delete that one problematic cache but this PR is a little more resilient to other weird behavior with that directory. --- .../workflows/devtools_regression_tests.yml | 4 +++ .github/workflows/runtime_build_and_test.yml | 30 +++++++++++++++++++ .../workflows/runtime_commit_artifacts.yml | 2 ++ .github/workflows/runtime_prereleases.yml | 2 ++ .github/workflows/shared_lint.yml | 8 +++++ 5 files changed, 46 insertions(+) diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml index 213f58218cc2b..64d6707aa3688 100644 --- a/.github/workflows/devtools_regression_tests.yml +++ b/.github/workflows/devtools_regression_tests.yml @@ -31,6 +31,8 @@ jobs: with: path: "**/node_modules" key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile working-directory: scripts/release @@ -63,6 +65,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index c59d990ba0ced..b9cbe4d447bbb 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -53,6 +53,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: node ./scripts/tasks/flow-ci ${{ matrix.flow_inline_config_shortname }} @@ -73,6 +75,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: | yarn generate-inline-fizz-runtime @@ -95,6 +99,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn flags @@ -144,6 +150,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }} @@ -173,6 +181,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn build --index=${{ matrix.worker_id }} --total=20 --r=${{ matrix.release_channel }} --ci env: @@ -243,6 +253,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -271,6 +283,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -314,6 +328,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -345,6 +361,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -373,6 +391,8 @@ jobs: with: path: "**/node_modules" key: fixtures_dom-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn working-directory: fixtures/dom @@ -413,6 +433,8 @@ jobs: with: path: "**/node_modules" key: fixtures_flight-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -469,6 +491,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -515,6 +539,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build uses: actions/download-artifact@v4 @@ -547,6 +573,8 @@ jobs: with: path: "**/node_modules" key: ${{ runner.arch }}-${{ runner.os }}-modules-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile working-directory: scripts/release @@ -586,6 +614,8 @@ jobs: with: path: "**/node_modules" key: runtime-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - name: Restore archived build for PR uses: actions/download-artifact@v4 diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 7842f07ba5888..4315256affe45 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -75,6 +75,8 @@ jobs: with: path: "**/node_modules" key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile name: yarn install (react) - run: yarn install --frozen-lockfile diff --git a/.github/workflows/runtime_prereleases.yml b/.github/workflows/runtime_prereleases.yml index 37516ea3cb19c..e52bed6bb16bf 100644 --- a/.github/workflows/runtime_prereleases.yml +++ b/.github/workflows/runtime_prereleases.yml @@ -41,6 +41,8 @@ jobs: with: path: "**/node_modules" key: runtime-release-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'scripts/release/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn install --frozen-lockfile working-directory: scripts/release diff --git a/.github/workflows/shared_lint.yml b/.github/workflows/shared_lint.yml index 00155e8e55976..36c1df9eb86f9 100644 --- a/.github/workflows/shared_lint.yml +++ b/.github/workflows/shared_lint.yml @@ -30,6 +30,8 @@ jobs: with: path: "**/node_modules" key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: yarn prettier-check @@ -48,6 +50,8 @@ jobs: with: path: "**/node_modules" key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: node ./scripts/tasks/eslint @@ -66,6 +70,8 @@ jobs: with: path: "**/node_modules" key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: ./scripts/ci/check_license.sh @@ -84,5 +90,7 @@ jobs: with: path: "**/node_modules" key: shared-lint-node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - name: Ensure clean build directory + run: rm -rf build - run: yarn install --frozen-lockfile - run: ./scripts/ci/test_print_warnings.sh From 988e2176702fca9b25113d9a8a3e7e3f484e16f2 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Thu, 14 Nov 2024 11:48:14 -0500 Subject: [PATCH 371/426] Turn on enableSiblingPrerendering in canary (#31541) In preparation for the next RC, I set this feature flag to true everywhere. I did not delete the feature flag yet, in case there are yet more bugs to be discovered. I also didn't remove the dynamic feature flag from the Meta builds; I'll let the Meta folks handle that. --- packages/shared/ReactFeatureFlags.js | 2 +- packages/shared/forks/ReactFeatureFlags.native-oss.js | 2 +- packages/shared/forks/ReactFeatureFlags.test-renderer.js | 2 +- .../shared/forks/ReactFeatureFlags.test-renderer.native-fb.js | 2 +- packages/shared/forks/ReactFeatureFlags.test-renderer.www.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 44d6e8629db83..02e2e796a359c 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -145,7 +145,7 @@ export const enableOwnerStacks = __EXPERIMENTAL__; export const enableShallowPropDiffing = false; -export const enableSiblingPrerendering = false; +export const enableSiblingPrerendering = true; /** * Enables an expiration time for retry lanes to avoid starvation. diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index d59e3f9698d4a..89c6413ac39db 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -83,7 +83,7 @@ export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; export const useModernStrictMode = true; -export const enableSiblingPrerendering = false; +export const enableSiblingPrerendering = true; // Profiling Only export const enableProfilerTimer = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index c27b2d6913dcd..04246165a8249 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -81,7 +81,7 @@ export const enableInfiniteRenderLoopDetection = false; export const renameElementSymbol = true; export const enableShallowPropDiffing = false; -export const enableSiblingPrerendering = false; +export const enableSiblingPrerendering = true; // TODO: This must be in sync with the main ReactFeatureFlags file because // the Test Renderer's value must be the same as the one used by the diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 170145c93db63..0198b7419a674 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -79,7 +79,7 @@ export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; export const useModernStrictMode = true; export const enableFabricCompleteRootInCommitPhase = false; -export const enableSiblingPrerendering = false; +export const enableSiblingPrerendering = true; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 46e939fd7319a..ebd7d03431f1f 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -92,7 +92,7 @@ export const renameElementSymbol = false; export const enableObjectFiber = false; export const enableOwnerStacks = false; export const enableShallowPropDiffing = false; -export const enableSiblingPrerendering = false; +export const enableSiblingPrerendering = true; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); From 7aa5dda3b3e4c2baa905a59b922ae7ec14734b24 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Thu, 14 Nov 2024 11:48:33 -0500 Subject: [PATCH 372/426] Bump RC version to 19.0.0-rc.1 (#31542) --- ReactVersions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactVersions.js b/ReactVersions.js index 731f5f336270e..ead100384e8bc 100644 --- a/ReactVersions.js +++ b/ReactVersions.js @@ -30,7 +30,7 @@ const canaryChannelLabel = 'rc'; // If the canaryChannelLabel is "rc", the build pipeline will use this to build // an RC version of the packages. -const rcNumber = 0; +const rcNumber = 1; const stablePackages = { 'eslint-plugin-react-hooks': '5.1.0', From b15135b9f59e4d40e1142342f97cfa18d228d0d4 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 14 Nov 2024 12:10:51 -0500 Subject: [PATCH 373/426] [ez] Update useMemoCache return type (#31539) Use `mixed` instead of `any` --- packages/react-debug-tools/src/ReactDebugHooks.js | 2 +- packages/react-reconciler/src/ReactFiberHooks.js | 2 +- packages/react-server/src/ReactFizzHooks.js | 2 +- packages/react/src/ReactHooks.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-debug-tools/src/ReactDebugHooks.js b/packages/react-debug-tools/src/ReactDebugHooks.js index 44d684003861b..b1e7a0272acea 100644 --- a/packages/react-debug-tools/src/ReactDebugHooks.js +++ b/packages/react-debug-tools/src/ReactDebugHooks.js @@ -560,7 +560,7 @@ function useId(): string { // useMemoCache is an implementation detail of Forget's memoization // it should not be called directly in user-generated code -function useMemoCache(size: number): Array { +function useMemoCache(size: number): Array { const fiber = currentFiber; // Don't throw, in case this is called from getPrimitiveStackCache if (fiber == null) { diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index 01f3b400adf70..174235fc76d65 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -1199,7 +1199,7 @@ function use(usable: Usable): T { throw new Error('An unsupported type was passed to use(): ' + String(usable)); } -function useMemoCache(size: number): Array { +function useMemoCache(size: number): Array { let memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared let updateQueue: FunctionComponentUpdateQueue | null = diff --git a/packages/react-server/src/ReactFizzHooks.js b/packages/react-server/src/ReactFizzHooks.js index 5a33617d2186a..78e114e373e6b 100644 --- a/packages/react-server/src/ReactFizzHooks.js +++ b/packages/react-server/src/ReactFizzHooks.js @@ -792,7 +792,7 @@ function useCacheRefresh(): (?() => T, ?T) => void { return unsupportedRefresh; } -function useMemoCache(size: number): Array { +function useMemoCache(size: number): Array { const data = new Array(size); for (let i = 0; i < size; i++) { data[i] = REACT_MEMO_CACHE_SENTINEL; diff --git a/packages/react/src/ReactHooks.js b/packages/react/src/ReactHooks.js index 956a2a96b44a1..dba0d4be0f6c5 100644 --- a/packages/react/src/ReactHooks.js +++ b/packages/react/src/ReactHooks.js @@ -212,7 +212,7 @@ export function use(usable: Usable): T { return dispatcher.use(usable); } -export function useMemoCache(size: number): Array { +export function useMemoCache(size: number): Array { const dispatcher = resolveDispatcher(); // $FlowFixMe[not-a-function] This is unstable, thus optional return dispatcher.useMemoCache(size); From 8657869999d3ed36cde45a4b2ef33fc815869295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 14 Nov 2024 13:05:20 -0500 Subject: [PATCH 374/426] Separate Tracks for Components and Phases (#31525) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we were showing Components inside each lane track but that meant that as soon as you expanded a lane you couldn't see the other line so you couldn't get an overview over how well things were scheduled. This instead moves all the Components into a single top-level track and renames the previous one to a "Scheduler" track group. Screenshot 2024-11-12 at 8 26 05 PM That way you can get an overview over what React is working on first and then right below see which Component is being worked on. Ideally the "Scheduler" track would be always expanded since each Track is always just a single row. Now you have to expand each lane to see the labels but then you're wasting a lot of vertical real estate. There's currently no option to create this with the Chrome performance.measure extensions. Screenshot 2024-11-12 at 8 26 16 PM --- .../src/ReactFiberPerformanceTrack.js | 118 ++++++++++-------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 3d52dcf4e1073..b80635423ab5f 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -21,14 +21,13 @@ const supportsUserTiming = // $FlowFixMe[method-unbinding] typeof performance.measure === 'function'; -const TRACK_GROUP = 'Components ⚛'; +const COMPONENTS_TRACK = 'Components ⚛'; // Reused to avoid thrashing the GC. const reusableComponentDevToolDetails = { dataType: 'track-entry', color: 'primary', - track: 'Blocking', // Lane - trackGroup: TRACK_GROUP, + track: COMPONENTS_TRACK, }; const reusableComponentOptions = { start: -0, @@ -38,9 +37,24 @@ const reusableComponentOptions = { }, }; +const LANES_TRACK_GROUP = 'Scheduler ⚛'; + +const reusableLaneDevToolDetails = { + dataType: 'track-entry', + color: 'primary', + track: 'Blocking', // Lane + trackGroup: LANES_TRACK_GROUP, +}; +const reusableLaneOptions = { + start: -0, + end: -0, + detail: { + devtools: reusableLaneDevToolDetails, + }, +}; + export function setCurrentTrackFromLanes(lanes: number): void { - reusableComponentDevToolDetails.track = - getGroupNameOfHighestPriorityLane(lanes); + reusableLaneDevToolDetails.track = getGroupNameOfHighestPriorityLane(lanes); } export function logComponentRender( @@ -107,21 +121,20 @@ export function logBlockingStart( renderStartTime: number, ): void { if (supportsUserTiming) { - reusableComponentDevToolDetails.track = 'Blocking'; + reusableLaneDevToolDetails.track = 'Blocking'; if (eventTime > 0 && eventType !== null) { // Log the time from the event timeStamp until we called setState. - reusableComponentDevToolDetails.color = 'secondary-dark'; - reusableComponentOptions.start = eventTime; - reusableComponentOptions.end = - updateTime > 0 ? updateTime : renderStartTime; - performance.measure(eventType, reusableComponentOptions); + reusableLaneDevToolDetails.color = 'secondary-dark'; + reusableLaneOptions.start = eventTime; + reusableLaneOptions.end = updateTime > 0 ? updateTime : renderStartTime; + performance.measure(eventType, reusableLaneOptions); } if (updateTime > 0) { // Log the time from when we called setState until we started rendering. - reusableComponentDevToolDetails.color = 'primary-light'; - reusableComponentOptions.start = updateTime; - reusableComponentOptions.end = renderStartTime; - performance.measure('Blocked', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'primary-light'; + reusableLaneOptions.start = updateTime; + reusableLaneOptions.end = renderStartTime; + performance.measure('Blocked', reusableLaneOptions); } } } @@ -134,43 +147,42 @@ export function logTransitionStart( renderStartTime: number, ): void { if (supportsUserTiming) { - reusableComponentDevToolDetails.track = 'Transition'; + reusableLaneDevToolDetails.track = 'Transition'; if (eventTime > 0 && eventType !== null) { // Log the time from the event timeStamp until we started a transition. - reusableComponentDevToolDetails.color = 'secondary-dark'; - reusableComponentOptions.start = eventTime; - reusableComponentOptions.end = + reusableLaneDevToolDetails.color = 'secondary-dark'; + reusableLaneOptions.start = eventTime; + reusableLaneOptions.end = startTime > 0 ? startTime : updateTime > 0 ? updateTime : renderStartTime; - performance.measure(eventType, reusableComponentOptions); + performance.measure(eventType, reusableLaneOptions); } if (startTime > 0) { // Log the time from when we started an async transition until we called setState or started rendering. - reusableComponentDevToolDetails.color = 'primary-dark'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = - updateTime > 0 ? updateTime : renderStartTime; - performance.measure('Action', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'primary-dark'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = updateTime > 0 ? updateTime : renderStartTime; + performance.measure('Action', reusableLaneOptions); } if (updateTime > 0) { // Log the time from when we called setState until we started rendering. - reusableComponentDevToolDetails.color = 'primary-light'; - reusableComponentOptions.start = updateTime; - reusableComponentOptions.end = renderStartTime; - performance.measure('Blocked', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'primary-light'; + reusableLaneOptions.start = updateTime; + reusableLaneOptions.end = renderStartTime; + performance.measure('Blocked', reusableLaneOptions); } } } export function logRenderPhase(startTime: number, endTime: number): void { if (supportsUserTiming) { - reusableComponentDevToolDetails.color = 'primary-dark'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = endTime; - performance.measure('Render', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'primary-dark'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = endTime; + performance.measure('Render', reusableLaneOptions); } } @@ -180,10 +192,10 @@ export function logSuspenseThrottlePhase( ): void { // This was inside a throttled Suspense boundary commit. if (supportsUserTiming) { - reusableComponentDevToolDetails.color = 'secondary-light'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = endTime; - performance.measure('Throttled', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'secondary-light'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = endTime; + performance.measure('Throttled', reusableLaneOptions); } } @@ -193,28 +205,28 @@ export function logSuspendedCommitPhase( ): void { // This means the commit was suspended on CSS or images. if (supportsUserTiming) { - reusableComponentDevToolDetails.color = 'secondary-light'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = endTime; - performance.measure('Suspended', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'secondary-light'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = endTime; + performance.measure('Suspended', reusableLaneOptions); } } export function logCommitPhase(startTime: number, endTime: number): void { if (supportsUserTiming) { - reusableComponentDevToolDetails.color = 'secondary-dark'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = endTime; - performance.measure('Commit', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'secondary-dark'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = endTime; + performance.measure('Commit', reusableLaneOptions); } } export function logPaintYieldPhase(startTime: number, endTime: number): void { if (supportsUserTiming) { - reusableComponentDevToolDetails.color = 'secondary-light'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = endTime; - performance.measure('Waiting for Paint', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'secondary-light'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = endTime; + performance.measure('Waiting for Paint', reusableLaneOptions); } } @@ -223,9 +235,9 @@ export function logPassiveCommitPhase( endTime: number, ): void { if (supportsUserTiming) { - reusableComponentDevToolDetails.color = 'secondary-dark'; - reusableComponentOptions.start = startTime; - reusableComponentOptions.end = endTime; - performance.measure('Remaining Effects', reusableComponentOptions); + reusableLaneDevToolDetails.color = 'secondary-dark'; + reusableLaneOptions.start = startTime; + reusableLaneOptions.end = endTime; + performance.measure('Remaining Effects', reusableLaneOptions); } } From 3644f0bd214b7c08a522cc9212dfca902777bf8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 14 Nov 2024 13:05:38 -0500 Subject: [PATCH 375/426] Use completedRenderEndTime as the start of the commit phase if it's an immediate commit (#31527) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't log a phase like "Throttled" or "Suspended" for this case so it can leave a tiny gap otherwise. This ensures it connects without a seam. Screenshot 2024-11-12 at 9 34 17 PM --- packages/react-reconciler/src/ReactFiberWorkLoop.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index bd30492fc0d0e..bffedf498bc28 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -3250,7 +3250,12 @@ function commitRootImpl( if (enableProfilerTimer && enableComponentPerformanceTrack) { recordCommitEndTime(); - logCommitPhase(commitStartTime, commitEndTime); + logCommitPhase( + suspendedCommitReason === IMMEDIATE_COMMIT + ? completedRenderEndTime + : commitStartTime, + commitEndTime, + ); } const rootDidHavePassiveEffects = rootDoesHavePassiveEffects; From 3c15d219aa6a573504d42ec0bcff1c0c9f35a842 Mon Sep 17 00:00:00 2001 From: Niklas Mollenhauer Date: Thu, 14 Nov 2024 21:43:36 +0100 Subject: [PATCH 376/426] [compiler] Disable emit of .tsbuildinfo (#31459) ## Summary `@rollup/plugin-typescript` emits a warning while building, hinting that `outputToFilesystem` defaults to true. Although "noEmit" is set to `true` for the tsconfig, rollup writes a `dist/.tsbuildinfo`. That file is then also shipped inside the npm module and doesn't offer any benefit for library consumers. Setting this option to false results in the file not being written and thus omitted from the npm module. ## How did you test this change? `dist/.tsbuildinfo` is not emitted any more. --- compiler/packages/babel-plugin-react-compiler/package.json | 3 ++- compiler/packages/babel-plugin-react-compiler/rollup.config.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/packages/babel-plugin-react-compiler/package.json b/compiler/packages/babel-plugin-react-compiler/package.json index 2e7013577c9a3..3d14518b88d70 100644 --- a/compiler/packages/babel-plugin-react-compiler/package.json +++ b/compiler/packages/babel-plugin-react-compiler/package.json @@ -5,7 +5,8 @@ "main": "dist/index.js", "license": "MIT", "files": [ - "dist" + "dist", + "!*.tsbuildinfo" ], "scripts": { "build": "rimraf dist && rollup --config --bundleConfigAsCjs", diff --git a/compiler/packages/babel-plugin-react-compiler/rollup.config.js b/compiler/packages/babel-plugin-react-compiler/rollup.config.js index b5d7567846f25..77e785c4641f2 100644 --- a/compiler/packages/babel-plugin-react-compiler/rollup.config.js +++ b/compiler/packages/babel-plugin-react-compiler/rollup.config.js @@ -28,6 +28,7 @@ const DEV_ROLLUP_CONFIG = { plugins: [ typescript({ tsconfig: './tsconfig.json', + outputToFilesystem: true, compilerOptions: { noEmit: true, }, From 5d89471ca6a74916bf345ef742e162c77672d2a2 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 14 Nov 2024 15:46:35 -0500 Subject: [PATCH 377/426] Export __COMPILER_RUNTIME in stable (#31540) In order to make use of the compiler in stable releases (eg React 19 RC, canary), we need to export the compiler runtime in the stable channel as well. --- packages/react/index.stable.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/index.stable.js b/packages/react/index.stable.js index a08110e809bd1..26e22c343223e 100644 --- a/packages/react/index.stable.js +++ b/packages/react/index.stable.js @@ -9,6 +9,7 @@ export { __CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, + __COMPILER_RUNTIME, act, Children, Component, From 4686872159e357accd092b195fb5cafceb980ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 14 Nov 2024 16:30:05 -0500 Subject: [PATCH 378/426] Log passive commit phase when it wasn't delayed (#31526) Fixes a bug. We're supposed to not log "Waiting for Paint" if the passive effect phase was forced since we weren't really waiting until the paint. Instead we just log an empty string when we force it to still ensure continuity. We should always log the passive phase. This check was in the wrong place. --- .../src/ReactFiberPerformanceTrack.js | 11 +++++++++-- packages/react-reconciler/src/ReactFiberWorkLoop.js | 10 ++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index b80635423ab5f..e1d75149b2425 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -221,12 +221,19 @@ export function logCommitPhase(startTime: number, endTime: number): void { } } -export function logPaintYieldPhase(startTime: number, endTime: number): void { +export function logPaintYieldPhase( + startTime: number, + endTime: number, + delayedUntilPaint: boolean, +): void { if (supportsUserTiming) { reusableLaneDevToolDetails.color = 'secondary-light'; reusableLaneOptions.start = startTime; reusableLaneOptions.end = endTime; - performance.measure('Waiting for Paint', reusableLaneOptions); + performance.measure( + delayedUntilPaint ? 'Waiting for Paint' : '', + reusableLaneOptions, + ); } } diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index bffedf498bc28..6d2ec2d0c8e61 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -3550,7 +3550,11 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) { let passiveEffectStartTime = 0; if (enableProfilerTimer && enableComponentPerformanceTrack) { passiveEffectStartTime = now(); - logPaintYieldPhase(commitEndTime, passiveEffectStartTime); + logPaintYieldPhase( + commitEndTime, + passiveEffectStartTime, + !!wasDelayedCommit, + ); } if (enableSchedulingProfiler) { @@ -3587,9 +3591,7 @@ function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) { if (enableProfilerTimer && enableComponentPerformanceTrack) { const passiveEffectsEndTime = now(); - if (wasDelayedCommit) { - logPassiveCommitPhase(passiveEffectStartTime, passiveEffectsEndTime); - } + logPassiveCommitPhase(passiveEffectStartTime, passiveEffectsEndTime); finalizeRender(lanes, passiveEffectsEndTime); } From c13986da7866a1a70a73b7ee05c87a9618ce6d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 14 Nov 2024 16:35:08 -0500 Subject: [PATCH 379/426] Fix Overlapping "message" Bug in Performance Track (#31528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When you schedule a microtask from render or effect and then call setState (or ping) from there, the "event" is the event that React scheduled (which will be a postMessage). The event time of this new render will be before the last render finished. We usually clamp these but in this scenario the update doesn't happen while a render is happening. Causing overlapping events. Before: Screenshot 2024-11-12 at 11 01 30 PM Therefore when we finalize a render we need to store the end of the last render so when we a new update comes in later with an event time earlier than that, we know to clamp it. There's also a special case here where when we enter the `RootDidNotComplete` or `RootSuspendedWithDelay` case we neither leave the root as in progress nor commit it. Those needs to finalize too. Really this should be modeled as a suspended track that we haven't added yet. That's the gap between "Blocked" and "message" below. After: Screenshot 2024-11-13 at 12 31 34 AM I also fixed an issue where we may log the same event name multiple times if we're rendering more than once in the same event. In this case I just leave a blank trace between the last commit and the next update. I also adding ignoring of the "message" event at all in these cases when the event is from React's scheduling itself. --- packages/react-art/src/ReactFiberConfigART.js | 2 + .../src/client/ReactFiberConfigDOM.js | 9 +++- .../src/ReactFiberConfigFabric.js | 2 + .../src/ReactFiberConfigNative.js | 2 + .../src/createReactNoop.js | 2 + .../src/ReactFiberPerformanceTrack.js | 6 ++- .../src/ReactFiberRootScheduler.js | 14 ++++++ .../src/ReactFiberWorkLoop.js | 38 +++++++++++++-- .../src/ReactProfilerTimer.js | 48 +++++++++++-------- .../ReactFiberHostContext-test.internal.js | 1 + .../src/forks/ReactFiberConfig.custom.js | 1 + .../src/ReactFiberConfigTestHost.js | 3 +- 12 files changed, 97 insertions(+), 31 deletions(-) diff --git a/packages/react-art/src/ReactFiberConfigART.js b/packages/react-art/src/ReactFiberConfigART.js index 33bbe055724d9..b88d6008c4bd2 100644 --- a/packages/react-art/src/ReactFiberConfigART.js +++ b/packages/react-art/src/ReactFiberConfigART.js @@ -363,6 +363,8 @@ export function resolveUpdatePriority(): EventPriority { return currentUpdatePriority || DefaultEventPriority; } +export function trackSchedulerEvent(): void {} + export function resolveEventType(): null | string { return null; } diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index af53a2a6acf47..e3f6ff56f6ecf 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -606,14 +606,19 @@ export function shouldAttemptEagerTransition(): boolean { return false; } +let schedulerEvent: void | Event = undefined; +export function trackSchedulerEvent(): void { + schedulerEvent = window.event; +} + export function resolveEventType(): null | string { const event = window.event; - return event ? event.type : null; + return event && event !== schedulerEvent ? event.type : null; } export function resolveEventTimeStamp(): number { const event = window.event; - return event ? event.timeStamp : -1.1; + return event && event !== schedulerEvent ? event.timeStamp : -1.1; } export const isPrimaryRenderer = true; diff --git a/packages/react-native-renderer/src/ReactFiberConfigFabric.js b/packages/react-native-renderer/src/ReactFiberConfigFabric.js index 10f7c6ecd84a3..2b0997d2e8b3f 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigFabric.js +++ b/packages/react-native-renderer/src/ReactFiberConfigFabric.js @@ -372,6 +372,8 @@ export function resolveUpdatePriority(): EventPriority { return DefaultEventPriority; } +export function trackSchedulerEvent(): void {} + export function resolveEventType(): null | string { return null; } diff --git a/packages/react-native-renderer/src/ReactFiberConfigNative.js b/packages/react-native-renderer/src/ReactFiberConfigNative.js index 1dc8c627b1ccb..774a84a7d63e9 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigNative.js +++ b/packages/react-native-renderer/src/ReactFiberConfigNative.js @@ -288,6 +288,8 @@ export function resolveUpdatePriority(): EventPriority { return DefaultEventPriority; } +export function trackSchedulerEvent(): void {} + export function resolveEventType(): null | string { return null; } diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 4c1bf05e54046..2e24c07932cac 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -531,6 +531,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { return currentEventPriority; }, + trackSchedulerEvent(): void {}, + resolveEventType(): null | string { return null; }, diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index e1d75149b2425..953e6ed30ac63 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -118,6 +118,7 @@ export function logBlockingStart( updateTime: number, eventTime: number, eventType: null | string, + eventIsRepeat: boolean, renderStartTime: number, ): void { if (supportsUserTiming) { @@ -127,7 +128,7 @@ export function logBlockingStart( reusableLaneDevToolDetails.color = 'secondary-dark'; reusableLaneOptions.start = eventTime; reusableLaneOptions.end = updateTime > 0 ? updateTime : renderStartTime; - performance.measure(eventType, reusableLaneOptions); + performance.measure(eventIsRepeat ? '' : eventType, reusableLaneOptions); } if (updateTime > 0) { // Log the time from when we called setState until we started rendering. @@ -144,6 +145,7 @@ export function logTransitionStart( updateTime: number, eventTime: number, eventType: null | string, + eventIsRepeat: boolean, renderStartTime: number, ): void { if (supportsUserTiming) { @@ -158,7 +160,7 @@ export function logTransitionStart( : updateTime > 0 ? updateTime : renderStartTime; - performance.measure(eventType, reusableLaneOptions); + performance.measure(eventIsRepeat ? '' : eventType, reusableLaneOptions); } if (startTime > 0) { // Log the time from when we started an async transition until we called setState or started rendering. diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 1f529d9e4df31..8756a9c89009c 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -18,6 +18,7 @@ import { disableSchedulerTimeoutInWorkLoop, enableProfilerTimer, enableProfilerNestedUpdatePhase, + enableComponentPerformanceTrack, enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import { @@ -64,6 +65,7 @@ import { supportsMicrotasks, scheduleMicrotask, shouldAttemptEagerTransition, + trackSchedulerEvent, } from './ReactFiberConfig'; import ReactSharedInternals from 'shared/ReactSharedInternals'; @@ -225,6 +227,12 @@ function flushSyncWorkAcrossRoots_impl( } function processRootScheduleInMicrotask() { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // Track the currently executing event if there is one so we can ignore this + // event when logging events. + trackSchedulerEvent(); + } + // This function is always called inside a microtask. It should never be // called synchronously. didScheduleMicrotask = false; @@ -428,6 +436,12 @@ function performWorkOnRootViaSchedulerTask( resetNestedUpdateFlag(); } + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // Track the currently executing event if there is one so we can ignore this + // event when logging events. + trackSchedulerEvent(); + } + // Flush any pending passive effects before deciding which lanes to work on, // in case they schedule additional work. const originalCallbackNode = root.callbackNode; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 6d2ec2d0c8e61..36189aea53ca4 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -90,6 +90,7 @@ import { setCurrentUpdatePriority, getCurrentUpdatePriority, resolveUpdatePriority, + trackSchedulerEvent, } from './ReactFiberConfig'; import {createWorkInProgress, resetWorkInProgress} from './ReactFiber'; @@ -229,13 +230,17 @@ import { } from './ReactFiberConcurrentUpdates'; import { + blockingClampTime, blockingUpdateTime, blockingEventTime, blockingEventType, + blockingEventIsRepeat, + transitionClampTime, transitionStartTime, transitionUpdateTime, transitionEventTime, transitionEventType, + transitionEventIsRepeat, clearBlockingTimers, clearTransitionTimers, clampBlockingTimers, @@ -938,6 +943,9 @@ export function performWorkOnRoot( } break; } else if (exitStatus === RootDidNotComplete) { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + finalizeRender(lanes, now()); + } // The render unwound without completing the tree. This happens in special // cases where need to exit the current render without producing a // consistent tree or committing. @@ -1130,6 +1138,9 @@ function finishConcurrentRender( // This is a transition, so we should exit without committing a // placeholder and without scheduling a timeout. Delay indefinitely // until we receive more data. + if (enableProfilerTimer && enableComponentPerformanceTrack) { + finalizeRender(lanes, now()); + } const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( @@ -1655,19 +1666,31 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber { if (includesSyncLane(lanes) || includesBlockingLane(lanes)) { logBlockingStart( - blockingUpdateTime, - blockingEventTime, + blockingUpdateTime >= 0 && blockingUpdateTime < blockingClampTime + ? blockingClampTime + : blockingUpdateTime, + blockingEventTime >= 0 && blockingEventTime < blockingClampTime + ? blockingClampTime + : blockingEventTime, blockingEventType, + blockingEventIsRepeat, renderStartTime, ); clearBlockingTimers(); } if (includesTransitionLane(lanes)) { logTransitionStart( - transitionStartTime, - transitionUpdateTime, - transitionEventTime, + transitionStartTime >= 0 && transitionStartTime < transitionClampTime + ? transitionClampTime + : transitionStartTime, + transitionUpdateTime >= 0 && transitionUpdateTime < transitionClampTime + ? transitionClampTime + : transitionUpdateTime, + transitionEventTime >= 0 && transitionEventTime < transitionClampTime + ? transitionClampTime + : transitionEventTime, transitionEventType, + transitionEventIsRepeat, renderStartTime, ); clearTransitionTimers(); @@ -3139,6 +3162,11 @@ function commitRootImpl( // with setTimeout pendingPassiveTransitions = transitions; scheduleCallback(NormalSchedulerPriority, () => { + if (enableProfilerTimer && enableComponentPerformanceTrack) { + // Track the currently executing event if there is one so we can ignore this + // event when logging events. + trackSchedulerEvent(); + } flushPassiveEffects(true); // This render triggered passive effects: release the root cache pool // *after* passive effects fire to avoid freeing a cache pool that may diff --git a/packages/react-reconciler/src/ReactProfilerTimer.js b/packages/react-reconciler/src/ReactProfilerTimer.js index e59b5cb8e56ed..93869c85148a8 100644 --- a/packages/react-reconciler/src/ReactProfilerTimer.js +++ b/packages/react-reconciler/src/ReactProfilerTimer.js @@ -36,14 +36,18 @@ export let componentEffectDuration: number = -0; export let componentEffectStartTime: number = -1.1; export let componentEffectEndTime: number = -1.1; +export let blockingClampTime: number = -0; export let blockingUpdateTime: number = -1.1; // First sync setState scheduled. export let blockingEventTime: number = -1.1; // Event timeStamp of the first setState. export let blockingEventType: null | string = null; // Event type of the first setState. +export let blockingEventIsRepeat: boolean = false; // TODO: This should really be one per Transition lane. +export let transitionClampTime: number = -0; export let transitionStartTime: number = -1.1; // First startTransition call before setState. export let transitionUpdateTime: number = -1.1; // First transition setState scheduled. export let transitionEventTime: number = -1.1; // Event timeStamp of the first transition. export let transitionEventType: null | string = null; // Event type of the first transition. +export let transitionEventIsRepeat: boolean = false; export function startUpdateTimerByLane(lane: Lane): void { if (!enableProfilerTimer || !enableComponentPerformanceTrack) { @@ -52,15 +56,25 @@ export function startUpdateTimerByLane(lane: Lane): void { if (isSyncLane(lane) || isBlockingLane(lane)) { if (blockingUpdateTime < 0) { blockingUpdateTime = now(); - blockingEventTime = resolveEventTimeStamp(); - blockingEventType = resolveEventType(); + const newEventTime = resolveEventTimeStamp(); + const newEventType = resolveEventType(); + blockingEventIsRepeat = + newEventTime === blockingEventTime && + newEventType === blockingEventType; + blockingEventTime = newEventTime; + blockingEventType = newEventType; } } else if (isTransitionLane(lane)) { if (transitionUpdateTime < 0) { transitionUpdateTime = now(); if (transitionStartTime < 0) { - transitionEventTime = resolveEventTimeStamp(); - transitionEventType = resolveEventType(); + const newEventTime = resolveEventTimeStamp(); + const newEventType = resolveEventType(); + transitionEventIsRepeat = + newEventTime === transitionEventTime && + newEventType === transitionEventType; + transitionEventTime = newEventTime; + transitionEventType = newEventType; } } } @@ -76,8 +90,13 @@ export function startAsyncTransitionTimer(): void { } if (transitionStartTime < 0 && transitionUpdateTime < 0) { transitionStartTime = now(); - transitionEventTime = resolveEventTimeStamp(); - transitionEventType = resolveEventType(); + const newEventTime = resolveEventTimeStamp(); + const newEventType = resolveEventType(); + transitionEventIsRepeat = + newEventTime === transitionEventTime && + newEventType === transitionEventType; + transitionEventTime = newEventTime; + transitionEventType = newEventType; } } @@ -115,12 +134,7 @@ export function clampBlockingTimers(finalTime: number): void { // If we had new updates come in while we were still rendering or committing, we don't want // those update times to create overlapping tracks in the performance timeline so we clamp // them to the end of the commit phase. - if (blockingUpdateTime >= 0 && blockingUpdateTime < finalTime) { - blockingUpdateTime = finalTime; - } - if (blockingEventTime >= 0 && blockingEventTime < finalTime) { - blockingEventTime = finalTime; - } + blockingClampTime = finalTime; } export function clampTransitionTimers(finalTime: number): void { @@ -130,15 +144,7 @@ export function clampTransitionTimers(finalTime: number): void { // If we had new updates come in while we were still rendering or committing, we don't want // those update times to create overlapping tracks in the performance timeline so we clamp // them to the end of the commit phase. - if (transitionStartTime >= 0 && transitionStartTime < finalTime) { - transitionStartTime = finalTime; - } - if (transitionUpdateTime >= 0 && transitionUpdateTime < finalTime) { - transitionUpdateTime = finalTime; - } - if (transitionEventTime >= 0 && transitionEventTime < finalTime) { - transitionEventTime = finalTime; - } + transitionClampTime = finalTime; } export function pushNestedEffectDurations(): number { diff --git a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js index 60726514474fb..fbbe9a3bf71af 100644 --- a/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactFiberHostContext-test.internal.js @@ -83,6 +83,7 @@ describe('ReactFiberHostContext', () => { } return DefaultEventPriority; }, + trackSchedulerEvent: function () {}, resolveEventType: function () { return null; }, diff --git a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js index 1f525d9a05c52..1ed0210e90ee5 100644 --- a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js @@ -73,6 +73,7 @@ export const getInstanceFromScope = $$$config.getInstanceFromScope; export const setCurrentUpdatePriority = $$$config.setCurrentUpdatePriority; export const getCurrentUpdatePriority = $$$config.getCurrentUpdatePriority; export const resolveUpdatePriority = $$$config.resolveUpdatePriority; +export const trackSchedulerEvent = $$$config.trackSchedulerEvent; export const resolveEventType = $$$config.resolveEventType; export const resolveEventTimeStamp = $$$config.resolveEventTimeStamp; export const shouldAttemptEagerTransition = diff --git a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js index cb38a985eb800..eaa0332fe8b29 100644 --- a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js +++ b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js @@ -224,10 +224,11 @@ export function resolveUpdatePriority(): EventPriority { } return DefaultEventPriority; } + +export function trackSchedulerEvent(): void {} export function resolveEventType(): null | string { return null; } - export function resolveEventTimeStamp(): number { return -1.1; } From b01722d58533e5e2664a71b70031e1c5390d813b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Thu, 14 Nov 2024 16:44:29 -0500 Subject: [PATCH 380/426] Format event with "warning" yellow and prefix with "Event: " (#31536) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's useful to quickly see where new events are kicking off new rendering. This uses the new "warning" color (yellow) to do that. This is to help distinguish it from the purple (secondary color) which is used for the commit phase which is more of a follow up and it's often that you have several rerenders within one event which makes it hard to tell a part where it starts and event otherwise. For the span marking between previous render within the same event and the next setState, I use secondary-light (light purple) since it's kind of still part of the same sequence at that point. It's usually a spawned render (e.g. setState in useEffect or microtask) but it can also be sequential flushSync. I was bothered by that the event name is the only thing that's lower case so I prefixed it with `Event: ` like the JS traces are. Screenshot 2024-11-13 at 7 15 45 PM It might be a little confusing why our track starts earlier than the JS one below in the "Main Thread" flamegraph which looks the same. That's because ours is the start of the event time which is when the click happens where as the Main Thread one is when the JS event loop gets around to processing the event. --- .../src/ReactFiberPerformanceTrack.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js index 953e6ed30ac63..859d5e6fa504a 100644 --- a/packages/react-reconciler/src/ReactFiberPerformanceTrack.js +++ b/packages/react-reconciler/src/ReactFiberPerformanceTrack.js @@ -125,10 +125,15 @@ export function logBlockingStart( reusableLaneDevToolDetails.track = 'Blocking'; if (eventTime > 0 && eventType !== null) { // Log the time from the event timeStamp until we called setState. - reusableLaneDevToolDetails.color = 'secondary-dark'; + reusableLaneDevToolDetails.color = eventIsRepeat + ? 'secondary-light' + : 'warning'; reusableLaneOptions.start = eventTime; reusableLaneOptions.end = updateTime > 0 ? updateTime : renderStartTime; - performance.measure(eventIsRepeat ? '' : eventType, reusableLaneOptions); + performance.measure( + eventIsRepeat ? '' : 'Event: ' + eventType, + reusableLaneOptions, + ); } if (updateTime > 0) { // Log the time from when we called setState until we started rendering. @@ -152,7 +157,9 @@ export function logTransitionStart( reusableLaneDevToolDetails.track = 'Transition'; if (eventTime > 0 && eventType !== null) { // Log the time from the event timeStamp until we started a transition. - reusableLaneDevToolDetails.color = 'secondary-dark'; + reusableLaneDevToolDetails.color = eventIsRepeat + ? 'secondary-light' + : 'warning'; reusableLaneOptions.start = eventTime; reusableLaneOptions.end = startTime > 0 @@ -160,7 +167,10 @@ export function logTransitionStart( : updateTime > 0 ? updateTime : renderStartTime; - performance.measure(eventIsRepeat ? '' : eventType, reusableLaneOptions); + performance.measure( + eventIsRepeat ? '' : 'Event: ' + eventType, + reusableLaneOptions, + ); } if (startTime > 0) { // Log the time from when we started an async transition until we called setState or started rendering. From 63cde684f5340b1ca73f6244501aac1c3d2c92a8 Mon Sep 17 00:00:00 2001 From: Zack Tanner <1939140+ztanner@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:03:59 -0800 Subject: [PATCH 381/426] (chore): copy fix in
- {errors > 0 && ( -
- - {errors} -
- )} - {warnings > 0 && ( -
- - {warnings} -
- )} - - - - - )} + {ownerID === null && (errors > 0 || warnings > 0) && ( + +
+ {errors > 0 && ( +
+ + {errors} +
+ )} + {warnings > 0 && ( +
+ + {warnings} +
+ )} + + + + + )} {!hideSettings && (
diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js index 8bde14e62e606..c48cdb58e3e4c 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/DebuggingSettings.js @@ -37,6 +37,10 @@ export default function DebuggingSettings({ const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] = useState(usedHookSettings.showInlineWarningsAndErrors); + useEffect(() => { + store.setShouldShowWarningsAndErrors(showInlineWarningsAndErrors); + }, [showInlineWarningsAndErrors]); + useEffect(() => { store.updateHookSettings({ appendComponentStack, diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js index 17514d94648ac..196ea806f6aac 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js @@ -43,21 +43,9 @@ type Context = { // Specified as a separate prop so it can trigger a re-render of FixedSizeList. lineHeight: number, - appendComponentStack: boolean, - setAppendComponentStack: (value: boolean) => void, - - breakOnConsoleErrors: boolean, - setBreakOnConsoleErrors: (value: boolean) => void, - parseHookNames: boolean, setParseHookNames: (value: boolean) => void, - hideConsoleLogsInStrictMode: boolean, - setHideConsoleLogsInStrictMode: (value: boolean) => void, - - showInlineWarningsAndErrors: boolean, - setShowInlineWarningsAndErrors: (value: boolean) => void, - theme: Theme, setTheme(value: Theme): void, @@ -176,7 +164,7 @@ function SettingsContextController({ bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled); }, [bridge, traceUpdatesEnabled]); - const value = useMemo( + const value: Context = useMemo( () => ({ displayDensity, lineHeight: From d2e9b9b4dc22639e2c51fb34e9388b9971ee3e27 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Wed, 25 Sep 2024 14:38:34 +0100 Subject: [PATCH 190/426] React DevTools 5.3.1 -> 6.0.0 (#31058) Full list of changes: * refactor: data source for errors and warnings tracking is now in Store ([hoxyq](https://github.com/hoxyq) in [#31010](https://github.com/facebook/react/pull/31010)) * fix: consider alternate as a key for componentLogsEntry when inspecting raw fiber instance ([hoxyq](https://github.com/hoxyq) in [#31009](https://github.com/facebook/react/pull/31009)) * Fix: profiling crashes #30661 #28838 ([EdmondChuiHW](https://github.com/EdmondChuiHW) in [#31024](https://github.com/facebook/react/pull/31024)) * chore: remove using local storage for persisting console settings on the frontend ([hoxyq](https://github.com/hoxyq) in [#31002](https://github.com/facebook/react/pull/31002)) * feat: display message if user ended up opening hook script ([hoxyq](https://github.com/hoxyq) in [#31000](https://github.com/facebook/react/pull/31000)) * feat: expose installHook with settings argument from react-devtools-core/backend ([hoxyq](https://github.com/hoxyq) in [#30987](https://github.com/facebook/react/pull/30987)) * chore: remove settings manager from react-devtools-core ([hoxyq](https://github.com/hoxyq) in [#30986](https://github.com/facebook/react/pull/30986)) * feat[react-devtools/extension]: use chrome.storage to persist settings across sessions ([hoxyq](https://github.com/hoxyq) in [#30636](https://github.com/facebook/react/pull/30636)) * refactor[react-devtools]: propagate settings from global hook object to frontend ([hoxyq](https://github.com/hoxyq) in [#30610](https://github.com/facebook/react/pull/30610)) * chore[react-devtools]: extract some utils into separate modules to unify implementations ([hoxyq](https://github.com/hoxyq) in [#30597](https://github.com/facebook/react/pull/30597)) * refactor[react-devtools]: move console patching to global hook ([hoxyq](https://github.com/hoxyq) in [#30596](https://github.com/facebook/react/pull/30596)) * refactor[react-devtools]: remove browserTheme from ConsolePatchSettings ([hoxyq](https://github.com/hoxyq) in [#30566](https://github.com/facebook/react/pull/30566)) * feat[react-devtools]: add settings to global hook object ([hoxyq](https://github.com/hoxyq) in [#30564](https://github.com/facebook/react/pull/30564)) * fix: add Error prefix to Error objects names ([hoxyq](https://github.com/hoxyq) in [#30969](https://github.com/facebook/react/pull/30969)) * Add enableComponentPerformanceTrack Flag ([sebmarkbage](https://github.com/sebmarkbage) in [#30960](https://github.com/facebook/react/pull/30960)) * fix[rdt/fiber/renderer.js]: getCurrentFiber can be injected as null ([hoxyq](https://github.com/hoxyq) in [#30968](https://github.com/facebook/react/pull/30968)) * disable `enableSiblingPrerendering` in experimental channel ([gnoff](https://github.com/gnoff) in [#30952](https://github.com/facebook/react/pull/30952)) * refactor[react-devtools]: initialize renderer interface early ([hoxyq](https://github.com/hoxyq) in [#30946](https://github.com/facebook/react/pull/30946)) * Start prerendering Suspense retries immediately ([acdlite](https://github.com/acdlite) in [#30934](https://github.com/facebook/react/pull/30934)) * refactor[Agent/Store]: Store to send messages only after Agent is initialized ([hoxyq](https://github.com/hoxyq) in [#30945](https://github.com/facebook/react/pull/30945)) * refactor[RendererInterface]: expose onErrorOrWarning and getComponentStack ([hoxyq](https://github.com/hoxyq) in [#30931](https://github.com/facebook/react/pull/30931)) * Implement getComponentStack and onErrorOrWarning for replayed Flight logs ([sebmarkbage](https://github.com/sebmarkbage) in [#30930](https://github.com/facebook/react/pull/30930)) * Use Unicode Atom Symbol instead of Atom Emoji ([sebmarkbage](https://github.com/sebmarkbage) in [#30832](https://github.com/facebook/react/pull/30832)) * Improve Layering Between Console and Renderer ([sebmarkbage](https://github.com/sebmarkbage) in [#30925](https://github.com/facebook/react/pull/30925)) * Add Map for Server Component Logs ([sebmarkbage](https://github.com/sebmarkbage) in [#30905](https://github.com/facebook/react/pull/30905)) * Delete fiberToFiberInstanceMap ([sebmarkbage](https://github.com/sebmarkbage) in [#30900](https://github.com/facebook/react/pull/30900)) * Add Flight Renderer ([sebmarkbage](https://github.com/sebmarkbage) in [#30906](https://github.com/facebook/react/pull/30906)) * Refactor Error / Warning Count Tracking ([sebmarkbage](https://github.com/sebmarkbage) in [#30899](https://github.com/facebook/react/pull/30899)) * [flow] Upgrade Flow to 0.245.2 ([SamChou19815](https://github.com/SamChou19815) in [#30919](https://github.com/facebook/react/pull/30919)) * Separate RDT Fusebox into single-panel entry points ([huntie](https://github.com/huntie) in [#30708](https://github.com/facebook/react/pull/30708)) * Build Updater List from the Commit instead of Map ([sebmarkbage](https://github.com/sebmarkbage) in [#30897](https://github.com/facebook/react/pull/30897)) * Simplify Context Change Tracking in Profiler ([sebmarkbage](https://github.com/sebmarkbage) in [#30896](https://github.com/facebook/react/pull/30896)) * Remove use of .alternate in root and recordProfilingDurations ([sebmarkbage](https://github.com/sebmarkbage) in [#30895](https://github.com/facebook/react/pull/30895)) * Handle reordered contexts in Profiler ([sebmarkbage](https://github.com/sebmarkbage) in [#30887](https://github.com/facebook/react/pull/30887)) * Refactor Forcing Fallback / Error of Suspense / Error Boundaries ([sebmarkbage](https://github.com/sebmarkbage) in [#30870](https://github.com/facebook/react/pull/30870)) * Avoid getFiberIDUnsafe in debug() Helper ([sebmarkbage](https://github.com/sebmarkbage) in [#30878](https://github.com/facebook/react/pull/30878)) * Include some Filtered Fiber Instances ([sebmarkbage](https://github.com/sebmarkbage) in [#30865](https://github.com/facebook/react/pull/30865)) * Track root instances in a root Map ([sebmarkbage](https://github.com/sebmarkbage) in [#30875](https://github.com/facebook/react/pull/30875)) * Track all public HostInstances in a Map ([sebmarkbage](https://github.com/sebmarkbage) in [#30831](https://github.com/facebook/react/pull/30831)) * Support VirtualInstances in findAllCurrentHostInstances ([sebmarkbage](https://github.com/sebmarkbage) in [#30853](https://github.com/facebook/react/pull/30853)) * Add Filtering of Environment Names ([sebmarkbage](https://github.com/sebmarkbage) in [#30850](https://github.com/facebook/react/pull/30850)) * Support secondary environment name when it changes ([sebmarkbage](https://github.com/sebmarkbage) in [#30842](https://github.com/facebook/react/pull/30842)) * Increase max payload for websocket in standalone app ([runeb](https://github.com/runeb) in [#30848](https://github.com/facebook/react/pull/30848)) * Filter Server Components ([sebmarkbage](https://github.com/sebmarkbage) in [#30839](https://github.com/facebook/react/pull/30839)) * Track virtual instances on the tracked path for selections ([sebmarkbage](https://github.com/sebmarkbage) in [#30802](https://github.com/facebook/react/pull/30802)) * Remove displayName from inspected data ([sebmarkbage](https://github.com/sebmarkbage) in [#30841](https://github.com/facebook/react/pull/30841)) * chore[react-devtools/hook]: remove unused native values ([hoxyq](https://github.com/hoxyq) in [#30827](https://github.com/facebook/react/pull/30827)) * chore[react-devtools/extensions]: remove unused storage permission ([hoxyq](https://github.com/hoxyq) in [#30826](https://github.com/facebook/react/pull/30826)) * fix[react-devtools/extensions]: fixed tabs API calls and displaying restricted access popup ([hoxyq](https://github.com/hoxyq) in [#30825](https://github.com/facebook/react/pull/30825)) * feat[react-devtools]: support Manifest v3 for Firefox extension ([hoxyq](https://github.com/hoxyq) in [#30824](https://github.com/facebook/react/pull/30824)) * Reconcile Fibers Against Previous Children Instances ([sebmarkbage](https://github.com/sebmarkbage) in [#30822](https://github.com/facebook/react/pull/30822)) * Remove findCurrentFiberUsingSlowPathByFiberInstance ([sebmarkbage](https://github.com/sebmarkbage) in [#30818](https://github.com/facebook/react/pull/30818)) * Track Tree Base Duration of Virtual Instances ([sebmarkbage](https://github.com/sebmarkbage) in [#30817](https://github.com/facebook/react/pull/30817)) * Use Owner Stacks to Implement View Source of a Server Component ([sebmarkbage](https://github.com/sebmarkbage) in [#30798](https://github.com/facebook/react/pull/30798)) * Make function inspection instant ([sebmarkbage](https://github.com/sebmarkbage) in [#30786](https://github.com/facebook/react/pull/30786)) * Make Functions Clickable to Jump to Definition ([sebmarkbage](https://github.com/sebmarkbage) in [#30769](https://github.com/facebook/react/pull/30769)) * Support REACT_LEGACY_ELEMENT_TYPE for formatting JSX ([sebmarkbage](https://github.com/sebmarkbage) in [#30779](https://github.com/facebook/react/pull/30779)) * Find owners from the parent path that matches the Fiber or ReactComponentInfo ([sebmarkbage](https://github.com/sebmarkbage) in [#30717](https://github.com/facebook/react/pull/30717)) * [Flight/DevTools] Pass the Server Component's "key" as Part of the ReactComponentInfo ([sebmarkbage](https://github.com/sebmarkbage) in [#30703](https://github.com/facebook/react/pull/30703)) * Hide props section if it is null ([sebmarkbage](https://github.com/sebmarkbage) in [#30696](https://github.com/facebook/react/pull/30696)) * Support Server Components in Tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30684](https://github.com/facebook/react/pull/30684)) * fix[react-devtools/InspectedElement]: fixed border stylings when some of the panels are not rendered ([hoxyq](https://github.com/hoxyq) in [#30676](https://github.com/facebook/react/pull/30676)) * Compute new reordered child set from the instance tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30668](https://github.com/facebook/react/pull/30668)) * Unmount instance by walking the instance tree instead of the fiber tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30665](https://github.com/facebook/react/pull/30665)) * Further Refactoring of Unmounts ([sebmarkbage](https://github.com/sebmarkbage) in [#30658](https://github.com/facebook/react/pull/30658)) * Remove lodash.throttle ([sebmarkbage](https://github.com/sebmarkbage) in [#30657](https://github.com/facebook/react/pull/30657)) * Unmount by walking previous nodes no longer in the new tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30644](https://github.com/facebook/react/pull/30644)) * Build up DevTools Instance Shadow Tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30625](https://github.com/facebook/react/pull/30625)) * chore[packages/react-devtools]: remove unused index.js ([hoxyq](https://github.com/hoxyq) in [#30579](https://github.com/facebook/react/pull/30579)) * Track DOM nodes to Fiber map for HostHoistable Resources ([sebmarkbage](https://github.com/sebmarkbage) in [#30590](https://github.com/facebook/react/pull/30590)) * Rename mountFiberRecursively/updateFiberRecursively ([sebmarkbage](https://github.com/sebmarkbage) in [#30586](https://github.com/facebook/react/pull/30586)) * Allow Highlighting/Inspect HostSingletons/Hoistables and Resources ([sebmarkbage](https://github.com/sebmarkbage) in [#30584](https://github.com/facebook/react/pull/30584)) * chore[react-devtools]: add global for native and use it to fork backend implementation ([hoxyq](https://github.com/hoxyq) in [#30533](https://github.com/facebook/react/pull/30533)) * Enable pointEvents while scrolling ([sebmarkbage](https://github.com/sebmarkbage) in [#30560](https://github.com/facebook/react/pull/30560)) * Make Element Inspection Feel Snappy ([sebmarkbage](https://github.com/sebmarkbage) in [#30555](https://github.com/facebook/react/pull/30555)) * Track the parent DevToolsInstance while mounting a tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30542](https://github.com/facebook/react/pull/30542)) * Add DevToolsInstance to Store Stateful Information ([sebmarkbage](https://github.com/sebmarkbage) in [#30517](https://github.com/facebook/react/pull/30517)) * Implement "best renderer" by taking the inner most matched node ([sebmarkbage](https://github.com/sebmarkbage) in [#30494](https://github.com/facebook/react/pull/30494)) * Rename NativeElement to HostInstance in the Bridge ([sebmarkbage](https://github.com/sebmarkbage) in [#30491](https://github.com/facebook/react/pull/30491)) * Rename Fiber to Element in the Bridge Protocol and RendererInterface ([sebmarkbage](https://github.com/sebmarkbage) in [#30490](https://github.com/facebook/react/pull/30490)) * Stop filtering owner stacks ([sebmarkbage](https://github.com/sebmarkbage) in [#30438](https://github.com/facebook/react/pull/30438)) * [Fiber] Call life-cycles with a react-stack-bottom-frame stack frame ([sebmarkbage](https://github.com/sebmarkbage) in [#30429](https://github.com/facebook/react/pull/30429)) * [Flight] Prefix owner stacks added to the console.log with the current stack ([sebmarkbage](https://github.com/sebmarkbage) in [#30427](https://github.com/facebook/react/pull/30427)) * [BE] switch to hermes parser for prettier ([kassens](https://github.com/kassens) in [#30421](https://github.com/facebook/react/pull/30421)) * Implement Owner Stacks ([sebmarkbage](https://github.com/sebmarkbage) in [#30417](https://github.com/facebook/react/pull/30417)) * [BE] upgrade prettier to 3.3.3 ([kassens](https://github.com/kassens) in [#30420](https://github.com/facebook/react/pull/30420)) * [ci] Add yarn_test_build job to gh actions * [Fizz] Refactor Component Stack Nodes ([sebmarkbage](https://github.com/sebmarkbage) in [#30298](https://github.com/facebook/react/pull/30298)) * Print component stacks as error objects to get source mapping ([sebmarkbage](https://github.com/sebmarkbage) in [#30289](https://github.com/facebook/react/pull/30289)) * Upgrade flow to 0.235.0 ([kassens](https://github.com/kassens) in [#30118](https://github.com/facebook/react/pull/30118)) * fix: path handling in react devtools ([Jack-Works](https://github.com/Jack-Works) in [#29199](https://github.com/facebook/react/pull/29199)) --- packages/react-devtools-core/package.json | 2 +- .../chrome/manifest.json | 4 +-- .../edge/manifest.json | 4 +-- .../firefox/manifest.json | 2 +- packages/react-devtools-inline/package.json | 2 +- packages/react-devtools-timeline/package.json | 2 +- packages/react-devtools/CHANGELOG.md | 32 +++++++++++++++++++ packages/react-devtools/package.json | 4 +-- 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/packages/react-devtools-core/package.json b/packages/react-devtools-core/package.json index 4c7f54775f6ba..23167fa377847 100644 --- a/packages/react-devtools-core/package.json +++ b/packages/react-devtools-core/package.json @@ -1,6 +1,6 @@ { "name": "react-devtools-core", - "version": "5.3.1", + "version": "6.0.0", "description": "Use react-devtools outside of the browser", "license": "MIT", "main": "./dist/backend.js", diff --git a/packages/react-devtools-extensions/chrome/manifest.json b/packages/react-devtools-extensions/chrome/manifest.json index 1ab43194f2620..f0209aaa73eed 100644 --- a/packages/react-devtools-extensions/chrome/manifest.json +++ b/packages/react-devtools-extensions/chrome/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Chrome Developer Tools.", - "version": "5.3.1", - "version_name": "5.3.1", + "version": "6.0.0", + "version_name": "6.0.0", "minimum_chrome_version": "102", "icons": { "16": "icons/16-production.png", diff --git a/packages/react-devtools-extensions/edge/manifest.json b/packages/react-devtools-extensions/edge/manifest.json index bd03dea08efb3..ca4d56b4453e9 100644 --- a/packages/react-devtools-extensions/edge/manifest.json +++ b/packages/react-devtools-extensions/edge/manifest.json @@ -2,8 +2,8 @@ "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Microsoft Edge Developer Tools.", - "version": "5.3.1", - "version_name": "5.3.1", + "version": "6.0.0", + "version_name": "6.0.0", "minimum_chrome_version": "102", "icons": { "16": "icons/16-production.png", diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json index 8a5a272fb4500..52f89104b4f80 100644 --- a/packages/react-devtools-extensions/firefox/manifest.json +++ b/packages/react-devtools-extensions/firefox/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "React Developer Tools", "description": "Adds React debugging tools to the Firefox Developer Tools.", - "version": "5.3.1", + "version": "6.0.0", "browser_specific_settings": { "gecko": { "id": "@react-devtools", diff --git a/packages/react-devtools-inline/package.json b/packages/react-devtools-inline/package.json index ead4c18380047..f0eadaf7e6d9e 100644 --- a/packages/react-devtools-inline/package.json +++ b/packages/react-devtools-inline/package.json @@ -1,6 +1,6 @@ { "name": "react-devtools-inline", - "version": "5.3.1", + "version": "6.0.0", "description": "Embed react-devtools within a website", "license": "MIT", "main": "./dist/backend.js", diff --git a/packages/react-devtools-timeline/package.json b/packages/react-devtools-timeline/package.json index b9a8aab901d54..883aad785f6b2 100644 --- a/packages/react-devtools-timeline/package.json +++ b/packages/react-devtools-timeline/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "react-devtools-timeline", - "version": "5.3.1", + "version": "6.0.0", "license": "MIT", "dependencies": { "@elg/speedscope": "1.9.0-a6f84db", diff --git a/packages/react-devtools/CHANGELOG.md b/packages/react-devtools/CHANGELOG.md index bfebd3ea0a705..aab41edf090f3 100644 --- a/packages/react-devtools/CHANGELOG.md +++ b/packages/react-devtools/CHANGELOG.md @@ -4,6 +4,38 @@ --- +### 6.0.0 +September 25, 2024 + +#### Features +* Support Server Components in Tree ([sebmarkbage](https://github.com/sebmarkbage) in [#30684](https://github.com/facebook/react/pull/30684)) +* feat: expose installHook with settings argument from react-devtools-core/backend ([hoxyq](https://github.com/hoxyq) in [#30987](https://github.com/facebook/react/pull/30987)) +* Add Filtering of Environment Names ([sebmarkbage](https://github.com/sebmarkbage) in [#30850](https://github.com/facebook/react/pull/30850)) +* Support secondary environment name when it changes ([sebmarkbage](https://github.com/sebmarkbage) in [#30842](https://github.com/facebook/react/pull/30842)) +* Filter Server Components ([sebmarkbage](https://github.com/sebmarkbage) in [#30839](https://github.com/facebook/react/pull/30839)) +* Make function inspection instant ([sebmarkbage](https://github.com/sebmarkbage) in [#30786](https://github.com/facebook/react/pull/30786)) +* Make Functions Clickable to Jump to Definition ([sebmarkbage](https://github.com/sebmarkbage) in [#30769](https://github.com/facebook/react/pull/30769)) +* [Flight/DevTools] Pass the Server Component's "key" as Part of the ReactComponentInfo ([sebmarkbage](https://github.com/sebmarkbage) in [#30703](https://github.com/facebook/react/pull/30703)) +* Make Element Inspection Feel Snappy ([sebmarkbage](https://github.com/sebmarkbage) in [#30555](https://github.com/facebook/react/pull/30555)) +* Print component stacks as error objects to get source mapping ([sebmarkbage](https://github.com/sebmarkbage) in [#30289](https://github.com/facebook/react/pull/30289)) + +#### Bugfixes +* Fix: profiling crashes #30661 #28838 ([EdmondChuiHW](https://github.com/EdmondChuiHW) in [#31024](https://github.com/facebook/react/pull/31024)) +* chore: remove settings manager from react-devtools-core ([hoxyq](https://github.com/hoxyq) in [#30986](https://github.com/facebook/react/pull/30986)) +* fix[react-devtools/extensions]: fixed tabs API calls and displaying restricted access popup ([hoxyq](https://github.com/hoxyq) in [#30825](https://github.com/facebook/react/pull/30825)) +* fix[react-devtools/InspectedElement]: fixed border stylings when some of the panels are not rendered ([hoxyq](https://github.com/hoxyq) in [#30676](https://github.com/facebook/react/pull/30676)) +* fix: path handling in react devtools ([Jack-Works](https://github.com/Jack-Works) in [#29199](https://github.com/facebook/react/pull/29199)) + +#### Other +* feat: display message if user ended up opening hook script ([hoxyq](https://github.com/hoxyq) in [#31000](https://github.com/facebook/react/pull/31000)) +* refactor[react-devtools]: move console patching to global hook ([hoxyq](https://github.com/hoxyq) in [#30596](https://github.com/facebook/react/pull/30596)) +* refactor[react-devtools]: initialize renderer interface early ([hoxyq](https://github.com/hoxyq) in [#30946](https://github.com/facebook/react/pull/30946)) +* Use Unicode Atom Symbol instead of Atom Emoji ([sebmarkbage](https://github.com/sebmarkbage) in [#30832](https://github.com/facebook/react/pull/30832)) +* feat[react-devtools]: support Manifest v3 for Firefox extension ([hoxyq](https://github.com/hoxyq) in [#30824](https://github.com/facebook/react/pull/30824)) +* Enable pointEvents while scrolling ([sebmarkbage](https://github.com/sebmarkbage) in [#30560](https://github.com/facebook/react/pull/30560)) + +--- + ### 5.3.1 July 3, 2024 diff --git a/packages/react-devtools/package.json b/packages/react-devtools/package.json index c9db18aca46a1..0972fd8c94e7a 100644 --- a/packages/react-devtools/package.json +++ b/packages/react-devtools/package.json @@ -1,6 +1,6 @@ { "name": "react-devtools", - "version": "5.3.1", + "version": "6.0.0", "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": "5.3.1", + "react-devtools-core": "6.0.0", "update-notifier": "^2.1.0" } } From f9ebd85a196948be17efdd6774b4d0464b3b1f53 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 25 Sep 2024 11:50:41 -0400 Subject: [PATCH 191/426] Increase nested update limit to 100 (#31061) We're seeing the limit hit in some tests after enabling sibling prerendering. Let's bump the limit so we can run more tests and gather more signal on the changes. When we understand the scope of the problem we can determine whether we need to change how the updates are counted in prerenders and/or fix specific areas of product code. --- packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js | 2 +- packages/react-dom/src/__tests__/ReactUpdates-test.js | 2 +- packages/react-reconciler/src/ReactFiberWorkLoop.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js b/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js index 26f56a938c551..57f2acfa53465 100644 --- a/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactLegacyUpdates-test.js @@ -1427,7 +1427,7 @@ describe('ReactLegacyUpdates', () => { } } - let limit = 55; + let limit = 105; await expect(async () => { await act(() => { ReactDOM.render(, container); diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index faf4b29551350..247a53531c659 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -1542,7 +1542,7 @@ describe('ReactUpdates', () => { } } - let limit = 55; + let limit = 105; const root = ReactDOMClient.createRoot(container); await expect(async () => { await act(() => { diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index c13b9c65a65a4..a0df584423e13 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -613,13 +613,13 @@ let pendingPassiveEffectsRenderEndTime: number = -0; // Profiling-only let pendingPassiveTransitions: Array | null = null; // Use these to prevent an infinite loop of nested updates -const NESTED_UPDATE_LIMIT = 50; +const NESTED_UPDATE_LIMIT = 100; let nestedUpdateCount: number = 0; let rootWithNestedUpdates: FiberRoot | null = null; let isFlushingPassiveEffects = false; let didScheduleUpdateDuringPassiveEffects = false; -const NESTED_PASSIVE_UPDATE_LIMIT = 50; +const NESTED_PASSIVE_UPDATE_LIMIT = 100; let nestedPassiveUpdateCount: number = 0; let rootWithPassiveNestedUpdates: FiberRoot | null = null; From 3c7667a694face1827356a7c90ee6f86a9c0baa0 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 25 Sep 2024 14:33:11 -0400 Subject: [PATCH 192/426] Unify perform{Sync,Concurrent}WorkOnRoot implementation (#31029) Over time the behavior of these two paths has converged to be essentially the same. So this merges them back into one function. This should save some code size and also make it harder for the behavior to accidentally diverge. (For the same reason, rolling out this change might expose some areas where we had already accidentally diverged.) --- .../src/ReactFiberRootScheduler.js | 95 +++++++++-- .../src/ReactFiberWorkLoop.js | 158 ++---------------- .../ReactSiblingPrerendering-test.js | 18 +- .../ReactSuspenseyCommitPhase-test.js | 20 +-- 4 files changed, 115 insertions(+), 176 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 15730d3e5b624..9f267e8345e39 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -15,6 +15,9 @@ import type {BatchConfigTransition} from './ReactFiberTracingMarkerComponent'; import { disableLegacyMode, enableDeferRootSchedulingToMicrotask, + disableSchedulerTimeoutInWorkLoop, + enableProfilerTimer, + enableProfilerNestedUpdatePhase, } from 'shared/ReactFeatureFlags'; import { NoLane, @@ -31,12 +34,12 @@ import { CommitContext, NoContext, RenderContext, + flushPassiveEffects, getExecutionContext, getWorkInProgressRoot, getWorkInProgressRootRenderLanes, isWorkLoopSuspendedOnData, - performConcurrentWorkOnRoot, - performSyncWorkOnRoot, + performWorkOnRoot, } from './ReactFiberWorkLoop'; import {LegacyRoot} from './ReactRootTags'; import { @@ -62,6 +65,10 @@ import { } from './ReactFiberConfig'; import ReactSharedInternals from 'shared/ReactSharedInternals'; +import { + resetNestedUpdateFlag, + syncNestedUpdateFlag, +} from './ReactProfilerTimer'; // A linked list of all the roots with pending work. In an idiomatic app, // there's only a single root, but we do support multi root apps, hence this @@ -387,7 +394,7 @@ function scheduleTaskForRootDuringMicrotask( const newCallbackNode = scheduleCallback( schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root), + performWorkOnRootViaSchedulerTask.bind(null, root), ); root.callbackPriority = newCallbackPriority; @@ -396,15 +403,67 @@ function scheduleTaskForRootDuringMicrotask( } } -export type RenderTaskFn = (didTimeout: boolean) => RenderTaskFn | null; +type RenderTaskFn = (didTimeout: boolean) => RenderTaskFn | null; -export function getContinuationForRoot( +function performWorkOnRootViaSchedulerTask( root: FiberRoot, - originalCallbackNode: mixed, + didTimeout: boolean, ): RenderTaskFn | null { - // This is called at the end of `performConcurrentWorkOnRoot` to determine - // if we need to schedule a continuation task. - // + // This is the entry point for concurrent tasks scheduled via Scheduler (and + // postTask, in the future). + + if (enableProfilerTimer && enableProfilerNestedUpdatePhase) { + resetNestedUpdateFlag(); + } + + // Flush any pending passive effects before deciding which lanes to work on, + // in case they schedule additional work. + const originalCallbackNode = root.callbackNode; + const didFlushPassiveEffects = flushPassiveEffects(); + if (didFlushPassiveEffects) { + // Something in the passive effect phase may have canceled the current task. + // Check if the task node for this root was changed. + if (root.callbackNode !== originalCallbackNode) { + // The current task was canceled. Exit. We don't need to call + // `ensureRootIsScheduled` because the check above implies either that + // there's a new task, or that there's no remaining work on this root. + return null; + } else { + // Current task was not canceled. Continue. + } + } + + // Determine the next lanes to work on, using the fields stored on the root. + // TODO: We already called getNextLanes when we scheduled the callback; we + // should be able to avoid calling it again by stashing the result on the + // root object. However, because we always schedule the callback during + // a microtask (scheduleTaskForRootDuringMicrotask), it's possible that + // an update was scheduled earlier during this same browser task (and + // therefore before the microtasks have run). That's because Scheduler batches + // together multiple callbacks into a single browser macrotask, without + // yielding to microtasks in between. We should probably change this to align + // with the postTask behavior (and literally use postTask when + // it's available). + const workInProgressRoot = getWorkInProgressRoot(); + const workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes(); + const lanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes, + ); + if (lanes === NoLanes) { + // No more work on this root. + return null; + } + + // Enter the work loop. + // TODO: We only check `didTimeout` defensively, to account for a Scheduler + // bug we're still investigating. Once the bug in Scheduler is fixed, + // we can remove this, since we track expiration ourselves. + const forceSync = !disableSchedulerTimeoutInWorkLoop && didTimeout; + performWorkOnRoot(root, lanes, forceSync); + + // The work loop yielded, but there may or may not be work left at the current + // priority. Need to determine whether we need to schedule a continuation. // Usually `scheduleTaskForRootDuringMicrotask` only runs inside a microtask; // however, since most of the logic for determining if we need a continuation // versus a new task is the same, we cheat a bit and call it here. This is @@ -414,11 +473,27 @@ export function getContinuationForRoot( if (root.callbackNode === originalCallbackNode) { // The task node scheduled for this root is the same one that's // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); + return performWorkOnRootViaSchedulerTask.bind(null, root); } return null; } +function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes) { + // This is the entry point for synchronous tasks that don't go + // through Scheduler. + const didFlushPassiveEffects = flushPassiveEffects(); + if (didFlushPassiveEffects) { + // If passive effects were flushed, exit to the outer work loop in the root + // scheduler, so we can recompute the priority. + return null; + } + if (enableProfilerTimer && enableProfilerNestedUpdatePhase) { + syncNestedUpdateFlag(); + } + const forceSync = true; + performWorkOnRoot(root, lanes, forceSync); +} + const fakeActCallbackNode = {}; function scheduleCallback( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index a0df584423e13..ba3270214c6a5 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -22,7 +22,6 @@ import type { TransitionAbort, } from './ReactFiberTracingMarkerComponent'; import type {OffscreenInstance} from './ReactFiberActivityComponent'; -import type {RenderTaskFn} from './ReactFiberRootScheduler'; import type {Resource} from './ReactFiberConfig'; import { @@ -32,7 +31,6 @@ import { enableProfilerNestedUpdatePhase, enableDebugTracing, enableSchedulingProfiler, - disableSchedulerTimeoutInWorkLoop, enableUpdaterTracking, enableCache, enableTransitionTracing, @@ -250,11 +248,9 @@ import { recordRenderTime, recordCommitTime, recordCommitEndTime, - resetNestedUpdateFlag, startProfilerTimer, stopProfilerTimerIfRunningAndRecordDuration, stopProfilerTimerIfRunningAndRecordIncompleteDuration, - syncNestedUpdateFlag, } from './ReactProfilerTimer'; import {setCurrentTrackFromLanes} from './ReactFiberPerformanceTrack'; @@ -308,7 +304,6 @@ import { ensureRootIsScheduled, flushSyncWorkOnAllRoots, flushSyncWorkOnLegacyRootsOnly, - getContinuationForRoot, requestTransitionLane, } from './ReactFiberRootScheduler'; import {getMaskedContext, getUnmaskedContext} from './ReactFiberContext'; @@ -890,59 +885,22 @@ export function isUnsafeClassRenderPhaseUpdate(fiber: Fiber): boolean { return (executionContext & RenderContext) !== NoContext; } -// This is the entry point for every concurrent task, i.e. anything that -// goes through Scheduler. -export function performConcurrentWorkOnRoot( +export function performWorkOnRoot( root: FiberRoot, - didTimeout: boolean, -): RenderTaskFn | null { - if (enableProfilerTimer && enableProfilerNestedUpdatePhase) { - resetNestedUpdateFlag(); - } - + lanes: Lanes, + forceSync: boolean, +): void { if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { throw new Error('Should not already be working.'); } - // Flush any pending passive effects before deciding which lanes to work on, - // in case they schedule additional work. - const originalCallbackNode = root.callbackNode; - const didFlushPassiveEffects = flushPassiveEffects(); - if (didFlushPassiveEffects) { - // Something in the passive effect phase may have canceled the current task. - // Check if the task node for this root was changed. - if (root.callbackNode !== originalCallbackNode) { - // The current task was canceled. Exit. We don't need to call - // `ensureRootIsScheduled` because the check above implies either that - // there's a new task, or that there's no remaining work on this root. - return null; - } else { - // Current task was not canceled. Continue. - } - } - - // Determine the next lanes to work on, using the fields stored - // on the root. - // TODO: This was already computed in the caller. Pass it as an argument. - let lanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes, - ); - if (lanes === NoLanes) { - // Defensive coding. This is never expected to happen. - return null; - } - // We disable time-slicing in some cases: if the work has been CPU-bound // for too long ("expired" work, to prevent starvation), or we're in // sync-updates-by-default mode. - // TODO: We only check `didTimeout` defensively, to account for a Scheduler - // bug we're still investigating. Once the bug in Scheduler is fixed, - // we can remove this, since we track expiration ourselves. const shouldTimeSlice = + !forceSync && !includesBlockingLane(lanes) && - !includesExpiredLane(root, lanes) && - (disableSchedulerTimeoutInWorkLoop || !didTimeout); + !includesExpiredLane(root, lanes); let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes); @@ -984,7 +942,10 @@ export function performConcurrentWorkOnRoot( } // Check if something threw - if (exitStatus === RootErrored) { + if ( + (disableLegacyMode || root.tag !== LegacyRoot) && + exitStatus === RootErrored + ) { const lanesThatJustErrored = lanes; const errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, @@ -1033,7 +994,6 @@ export function performConcurrentWorkOnRoot( } ensureRootIsScheduled(root); - return getContinuationForRoot(root, originalCallbackNode); } function recoverFromConcurrentError( @@ -1464,104 +1424,6 @@ function markRootSuspended( ); } -// This is the entry point for synchronous tasks that don't go -// through Scheduler -export function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes): null { - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error('Should not already be working.'); - } - - const didFlushPassiveEffects = flushPassiveEffects(); - if (didFlushPassiveEffects) { - // If passive effects were flushed, exit to the outer work loop in the root - // scheduler, so we can recompute the priority. - // TODO: We don't actually need this `ensureRootIsScheduled` call because - // this path is only reachable if the root is already part of the schedule. - // I'm including it only for consistency with the other exit points from - // this function. Can address in a subsequent refactor. - ensureRootIsScheduled(root); - return null; - } - - if (enableProfilerTimer && enableProfilerNestedUpdatePhase) { - syncNestedUpdateFlag(); - } - - let exitStatus = renderRootSync(root, lanes); - if ( - (disableLegacyMode || root.tag !== LegacyRoot) && - exitStatus === RootErrored - ) { - // If something threw an error, try rendering one more time. We'll render - // synchronously to block concurrent data mutations, and we'll includes - // all pending updates are included. If it still fails after the second - // attempt, we'll give up and commit the resulting tree. - const originallyAttemptedLanes = lanes; - const errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes, - ); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes, - ); - } - } - - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes, NoLane, false); - ensureRootIsScheduled(root); - return null; - } - - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended( - root, - lanes, - workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, - ); - ensureRootIsScheduled(root); - return null; - } - - let renderEndTime = 0; - if (enableProfilerTimer && enableComponentPerformanceTrack) { - renderEndTime = now(); - } - - // We now have a consistent tree. Because this is a sync render, we - // will commit it even if something suspended. - const finishedWork: Fiber = (root.current.alternate: any); - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions, - workInProgressRootDidIncludeRecursiveRenderUpdate, - workInProgressDeferredLane, - workInProgressRootInterleavedUpdatedLanes, - workInProgressSuspendedRetryLanes, - IMMEDIATE_COMMIT, - renderStartTime, - renderEndTime, - ); - - // Before exiting, make sure there's a callback scheduled for the next - // pending level. - ensureRootIsScheduled(root); - - return null; -} - export function flushRoot(root: FiberRoot, lanes: Lanes) { if (lanes !== NoLanes) { upgradePendingLanesToSync(root, lanes); diff --git a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js index 6c24fdc980285..37d907b0fdc65 100644 --- a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js @@ -349,6 +349,7 @@ describe('ReactSiblingPrerendering', () => {
}> +
@@ -370,10 +371,17 @@ describe('ReactSiblingPrerendering', () => { // is throttled because it's been less than a Just Noticeable Difference // since the outer fallback was committed. // - // In the meantime, we could choose to start prerendering B, but instead + // In the meantime, we could choose to start prerendering C, but instead // we wait for a JND to elapse and the commit to finish — it's not // worth discarding the work we've already done. - await waitForAll(['A', 'Suspend! [B]', 'Loading inner...']); + await waitForAll([ + 'A', + 'Suspend! [B]', + + // C is skipped because we're no longer in prerendering mode; there's + // a new fallback we can show. + 'Loading inner...', + ]); expect(root).toMatchRenderedOutput(
Loading outer...
); // Fire the timer to commit the outer fallback. @@ -385,8 +393,10 @@ describe('ReactSiblingPrerendering', () => {
, ); }); - // Once the outer fallback is committed, we can start prerendering B. - assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [B]'] : []); + // Once the inner fallback is committed, we can start prerendering C. + assertLog( + gate('enableSiblingPrerendering') ? ['Suspend! [B]', 'Suspend! [C]'] : [], + ); }); it( diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseyCommitPhase-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseyCommitPhase-test.js index 972416eddedb8..4dbba1bca21f0 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseyCommitPhase-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseyCommitPhase-test.js @@ -239,11 +239,7 @@ describe('ReactSuspenseyCommitPhase', () => { expect(root).toMatchRenderedOutput(); }); - // @TODO This isn't actually ideal behavior. We would really want the commit to suspend - // even if it is forced to be sync because we don't want to FOUC but refactoring the sync - // pathway is too risky to land right now so we just accept that we can still FOUC in this - // very specific case. - it('does not suspend commit during urgent initial mount at the root when sync rendering', async () => { + it('does suspend commit during urgent initial mount at the root when sync rendering', async () => { const root = ReactNoop.createRoot(); await act(async () => { ReactNoop.flushSync(() => { @@ -252,19 +248,15 @@ describe('ReactSuspenseyCommitPhase', () => { }); assertLog(['Image requested [A]']); expect(getSuspenseyThingStatus('A')).toBe('pending'); - // We would expect this to be null if we did in fact suspend this commit - expect(root).toMatchRenderedOutput(); + // Suspend the initial mount + expect(root).toMatchRenderedOutput(null); resolveSuspenseyThing('A'); expect(getSuspenseyThingStatus('A')).toBe('fulfilled'); expect(root).toMatchRenderedOutput(); }); - // @TODO This isn't actually ideal behavior. We would really want the commit to suspend - // even if it is forced to be sync because we don't want to FOUC but refactoring the sync - // pathway is too risky to land right now so we just accept that we can still FOUC in this - // very specific case. - it('does not suspend commit during urgent update at the root when sync rendering', async () => { + it('does suspend commit during urgent update at the root when sync rendering', async () => { const root = ReactNoop.createRoot(); await act(() => resolveSuspenseyThing('A')); expect(getSuspenseyThingStatus('A')).toBe('fulfilled'); @@ -283,8 +275,8 @@ describe('ReactSuspenseyCommitPhase', () => { }); assertLog(['Image requested [B]']); expect(getSuspenseyThingStatus('B')).toBe('pending'); - // We would expect this to be hidden if we did in fact suspend this commit - expect(root).toMatchRenderedOutput(); + // Suspend and remain on previous screen + expect(root).toMatchRenderedOutput(); resolveSuspenseyThing('B'); expect(getSuspenseyThingStatus('B')).toBe('fulfilled'); From 0f1856c49febe96923e469f98c0b123130ea015c Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 25 Sep 2024 16:31:44 -0400 Subject: [PATCH 193/426] Make prerendering always non-blocking (#31056) When a synchronous update suspends, and we prerender the siblings, the prerendering should be non-blocking so that we can immediately restart once the data arrives. This happens automatically when there's a Suspense boundary, because we immediately commit the boundary and then proceed to a Retry render, which are always concurrent. When there's not a Suspense boundary, there is no Retry, so we need to take care to switch from the synchronous work loop to the concurrent one, to enable time slicing. --- .../src/__tests__/ReactDOMFiberAsync-test.js | 2 +- .../src/ReactFiberCompleteWork.js | 5 +- .../react-reconciler/src/ReactFiberLane.js | 32 +- .../src/ReactFiberRootScheduler.js | 20 +- .../src/ReactFiberWorkLoop.js | 293 +++++++++++------- .../src/__tests__/ReactDeferredValue-test.js | 12 + .../ReactSiblingPrerendering-test.js | 71 +++++ 7 files changed, 298 insertions(+), 137 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index ee843996bef1c..027099d54707c 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -744,7 +744,7 @@ describe('ReactDOMFiberAsync', () => { // Because it suspended, it remains on the current path expect(div.textContent).toBe('/path/a'); }); - assertLog([]); + assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []); await act(async () => { resolvePromise(); diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index e3fba900dd116..b24351ac383b9 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -42,6 +42,7 @@ import { enableRenderableContext, passChildrenWhenCloningPersistedNodes, disableLegacyMode, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import {now} from './Scheduler'; @@ -622,7 +623,9 @@ function scheduleRetryEffect( // Track the lanes that have been scheduled for an immediate retry so that // we can mark them as suspended upon committing the root. - markSpawnedRetryLane(retryLane); + if (enableSiblingPrerendering) { + markSpawnedRetryLane(retryLane); + } } } diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index b8c051def4eef..b98019046e3c2 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -27,6 +27,7 @@ import { transitionLaneExpirationMs, retryLaneExpirationMs, disableLegacyMode, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import {isDevToolsPresent} from './ReactFiberDevToolsHook'; import {clz32} from './clz32'; @@ -270,11 +271,13 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (nonIdlePingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); } else { - // Nothing has been pinged. Check for lanes that need to be prewarmed. - if (!rootHasPendingCommit) { - const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes; - if (lanesToPrewarm !== NoLanes) { - nextLanes = getHighestPriorityLanes(lanesToPrewarm); + if (enableSiblingPrerendering) { + // Nothing has been pinged. Check for lanes that need to be prewarmed. + if (!rootHasPendingCommit) { + const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes; + if (lanesToPrewarm !== NoLanes) { + nextLanes = getHighestPriorityLanes(lanesToPrewarm); + } } } } @@ -294,11 +297,13 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (pingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(pingedLanes); } else { - // Nothing has been pinged. Check for lanes that need to be prewarmed. - if (!rootHasPendingCommit) { - const lanesToPrewarm = pendingLanes & ~warmLanes; - if (lanesToPrewarm !== NoLanes) { - nextLanes = getHighestPriorityLanes(lanesToPrewarm); + if (enableSiblingPrerendering) { + // Nothing has been pinged. Check for lanes that need to be prewarmed. + if (!rootHasPendingCommit) { + const lanesToPrewarm = pendingLanes & ~warmLanes; + if (lanesToPrewarm !== NoLanes) { + nextLanes = getHighestPriorityLanes(lanesToPrewarm); + } } } } @@ -760,12 +765,14 @@ export function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didSkipSuspendedSiblings: boolean, + didAttemptEntireTree: boolean, ) { + // TODO: Split this into separate functions for marking the root at the end of + // a render attempt versus suspending while the root is still in progress. root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; - if (!didSkipSuspendedSiblings) { + if (enableSiblingPrerendering && didAttemptEntireTree) { // Mark these lanes as warm so we know there's nothing else to work on. root.warmLanes |= suspendedLanes; } else { @@ -876,6 +883,7 @@ export function markRootFinished( // suspended) instead of the regular mode (i.e. unwind and skip the siblings // as soon as something suspends to unblock the rest of the update). if ( + enableSiblingPrerendering && suspendedRetryLanes !== NoLanes && // Note that we only do this if there were no updates since we started // rendering. This mirrors the logic in markRootUpdated — whenever we diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 9f267e8345e39..39f6f466ed983 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -18,6 +18,7 @@ import { disableSchedulerTimeoutInWorkLoop, enableProfilerTimer, enableProfilerNestedUpdatePhase, + enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import { NoLane, @@ -29,6 +30,7 @@ import { markStarvedLanesAsExpired, claimNextTransitionLane, getNextLanesToFlushSync, + checkIfRootIsPrerendering, } from './ReactFiberLane'; import { CommitContext, @@ -206,7 +208,10 @@ function flushSyncWorkAcrossRoots_impl( ? workInProgressRootRenderLanes : NoLanes, ); - if (includesSyncLane(nextLanes)) { + if ( + includesSyncLane(nextLanes) && + !checkIfRootIsPrerendering(root, nextLanes) + ) { // This root has pending sync work. Flush it now. didPerformSomeWork = true; performSyncWorkOnRoot(root, nextLanes); @@ -341,7 +346,13 @@ function scheduleTaskForRootDuringMicrotask( } // Schedule a new callback in the host environment. - if (includesSyncLane(nextLanes)) { + if ( + includesSyncLane(nextLanes) && + // If we're prerendering, then we should use the concurrent work loop + // even if the lanes are synchronous, so that prerendering never blocks + // the main thread. + !(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes)) + ) { // Synchronous work is always flushed at the end of the microtask, so we // don't need to schedule an additional task. if (existingCallbackNode !== null) { @@ -375,9 +386,10 @@ function scheduleTaskForRootDuringMicrotask( let schedulerPriorityLevel; switch (lanesToEventPriority(nextLanes)) { + // Scheduler does have an "ImmediatePriority", but now that we use + // microtasks for sync work we no longer use that. Any sync work that + // reaches this path is meant to be time sliced. case DiscreteEventPriority: - schedulerPriorityLevel = ImmediateSchedulerPriority; - break; case ContinuousEventPriority: schedulerPriorityLevel = UserBlockingSchedulerPriority; break; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index ba3270214c6a5..5206caa5c0f76 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -765,11 +765,12 @@ export function scheduleUpdateOnFiber( // The incoming update might unblock the current render. Interrupt the // current attempt and restart from the top. prepareFreshStack(root, NoLanes); + const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } @@ -832,11 +833,12 @@ export function scheduleUpdateOnFiber( // effect of interrupting the current render and switching to the update. // TODO: Make sure this doesn't override pings that happen while we've // already started rendering. + const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } } @@ -898,100 +900,120 @@ export function performWorkOnRoot( // for too long ("expired" work, to prevent starvation), or we're in // sync-updates-by-default mode. const shouldTimeSlice = - !forceSync && - !includesBlockingLane(lanes) && - !includesExpiredLane(root, lanes); + (!forceSync && + !includesBlockingLane(lanes) && + !includesExpiredLane(root, lanes)) || + // If we're prerendering, then we should use the concurrent work loop + // even if the lanes are synchronous, so that prerendering never blocks + // the main thread. + // TODO: We should consider doing this whenever a sync lane is suspended, + // even for regular pings. + (enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes)); + let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); + : renderRootSync(root, lanes, true); - if (exitStatus !== RootInProgress) { + do { let renderWasConcurrent = shouldTimeSlice; - do { - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended( + if (exitStatus === RootInProgress) { + // Render phase is still in progress. + if ( + enableSiblingPrerendering && + workInProgressRootIsPrerendering && + !shouldTimeSlice + ) { + // We're in prerendering mode, but time slicing is not enabled. This + // happens when something suspends during a synchronous update. Exit the + // the work loop. When we resume, we'll use the concurrent work loop so + // that prerendering is non-blocking. + // + // Mark the root as suspended. Usually we do this at the end of the + // render phase, but we do it here so that we resume in + // prerendering mode. + // TODO: Consider always calling markRootSuspended immediately. + // Needs to be *after* we attach a ping listener, though. + const didAttemptEntireTree = false; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + } + break; + } else if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + } else { + // The render completed. + + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + const finishedWork: Fiber = (root.current.alternate: any); + if ( + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) + ) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes, false); + // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + renderWasConcurrent = false; + // Need to check the exit status again. + continue; + } + + // Check if something threw + if ( + (disableLegacyMode || root.tag !== LegacyRoot) && + exitStatus === RootErrored + ) { + const lanesThatJustErrored = lanes; + const errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, - lanes, - NoLane, - workInProgressRootDidSkipSuspendedSiblings, + lanesThatJustErrored, ); - } else { - // The render completed. - - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - const finishedWork: Fiber = (root.current.alternate: any); - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); - // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - renderWasConcurrent = false; - // Need to check the exit status again. - continue; - } - - // Check if something threw - if ( - (disableLegacyMode || root.tag !== LegacyRoot) && - exitStatus === RootErrored - ) { - const lanesThatJustErrored = lanes; - const errorRetryLanes = getLanesToRetrySynchronouslyOnError( + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( root, lanesThatJustErrored, + errorRetryLanes, ); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - lanesThatJustErrored, - errorRetryLanes, - ); - renderWasConcurrent = false; - // Need to check the exit status again. - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } else { - // The root errored yet again. Proceed to commit the tree. - } + renderWasConcurrent = false; + // Need to check the exit status again. + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; + } else { + // The root errored yet again. Proceed to commit the tree. } } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - markRootSuspended( - root, - lanes, - NoLane, - workInProgressRootDidSkipSuspendedSiblings, - ); - break; - } - - // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. - finishConcurrentRender(root, exitStatus, finishedWork, lanes); } - break; - } while (true); - } + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + // Since this is a fatal error, we're going to pretend we attempted + // the entire tree, to avoid scheduling a prerender. + const didAttemptEntireTree = true; + markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); + break; + } + + // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } + break; + } while (true); ensureRootIsScheduled(root); } @@ -1024,7 +1046,7 @@ function recoverFromConcurrentError( rootWorkInProgress.flags |= ForceClientRender; } - const exitStatus = renderRootSync(root, errorRetryLanes); + const exitStatus = renderRootSync(root, errorRetryLanes, false); if (exitStatus !== RootErrored) { // Successfully finished rendering on retry @@ -1108,11 +1130,13 @@ function finishConcurrentRender( // This is a transition, so we should exit without committing a // placeholder and without scheduling a timeout. Delay indefinitely // until we receive more data. + const didAttemptEntireTree = + !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); return; } @@ -1168,11 +1192,13 @@ function finishConcurrentRender( // Don't bother with a very short suspense time. if (msUntilTimeout > 10) { + const didAttemptEntireTree = + !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); const nextLanes = getNextLanes(root, NoLanes); @@ -1284,7 +1310,8 @@ function commitRootWhenReady( SUSPENDED_COMMIT, ), ); - markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings); + const didAttemptEntireTree = !didSkipSuspendedSiblings; + markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree); return; } } @@ -1407,7 +1434,7 @@ function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didSkipSuspendedSiblings: boolean, + didAttemptEntireTree: boolean, ) { // When suspending, we should always exclude lanes that were pinged or (more // rarely, since we try to avoid it) updated during the render phase. @@ -1416,12 +1443,7 @@ function markRootSuspended( suspendedLanes, workInProgressRootInterleavedUpdatedLanes, ); - _markRootSuspended( - root, - suspendedLanes, - spawnedLane, - didSkipSuspendedSiblings, - ); + _markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree); } export function flushRoot(root: FiberRoot, lanes: Lanes) { @@ -1963,7 +1985,12 @@ export function renderDidSuspendDelayIfPossible(): void { if ( !workInProgressRootDidSkipSuspendedSiblings && - !includesBlockingLane(workInProgressRootRenderLanes) + // Check if the root will be blocked from committing. + // TODO: Consider aligning this better with the rest of the logic. Maybe + // we should only set the exit status to RootSuspendedWithDelay if this + // condition is true? And remove the equivalent checks elsewhere. + (includesOnlyTransitions(workInProgressRootRenderLanes) || + getSuspenseHandler() === null) ) { // This render may not have originally been scheduled as a prerender, but // something suspended inside the visible part of the tree, which means we @@ -1989,11 +2016,12 @@ export function renderDidSuspendDelayIfPossible(): void { // pinged or updated while we were rendering. // TODO: Consider unwinding immediately, using the // SuspendedOnHydration mechanism. + const didAttemptEntireTree = false; markRootSuspended( workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane, - workInProgressRootDidSkipSuspendedSiblings, + didAttemptEntireTree, ); } } @@ -2023,7 +2051,11 @@ export function renderHasNotSuspendedYet(): boolean { // TODO: Over time, this function and renderRootConcurrent have become more // and more similar. Not sure it makes sense to maintain forked paths. Consider // unifying them again. -function renderRootSync(root: FiberRoot, lanes: Lanes) { +function renderRootSync( + root: FiberRoot, + lanes: Lanes, + shouldYieldForPrerendering: boolean, +): RootExitStatus { const prevExecutionContext = executionContext; executionContext |= RenderContext; const prevDispatcher = pushDispatcher(root.containerInfo); @@ -2063,6 +2095,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { } let didSuspendInShell = false; + let exitStatus = workInProgressRootExitStatus; outer: do { try { if ( @@ -2084,16 +2117,37 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { // Selective hydration. An update flowed into a dehydrated tree. // Interrupt the current render so the work loop can switch to the // hydration lane. + // TODO: I think we might not need to reset the stack here; we can + // just yield and reset the stack when we re-enter the work loop, + // like normal. resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; + exitStatus = RootDidNotComplete; break outer; } case SuspendedOnImmediate: - case SuspendedOnData: { - if (!didSuspendInShell && getSuspenseHandler() === null) { + case SuspendedOnData: + case SuspendedOnDeprecatedThrowPromise: { + if (getSuspenseHandler() === null) { didSuspendInShell = true; } - // Intentional fallthrough + const reason = workInProgressSuspendedReason; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason); + if ( + enableSiblingPrerendering && + shouldYieldForPrerendering && + workInProgressRootIsPrerendering + ) { + // We've switched into prerendering mode. This implies that we + // suspended outside of a Suspense boundary, which means this + // render will be blocked from committing. Yield to the main + // thread so we can switch to prerendering using the concurrent + // work loop. + exitStatus = RootInProgress; + break outer; + } + break; } default: { // Unwind then continue with the normal work loop. @@ -2106,6 +2160,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { } } workLoopSync(); + exitStatus = workInProgressRootExitStatus; break; } catch (thrownValue) { handleThrow(root, thrownValue); @@ -2128,14 +2183,6 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { popDispatcher(prevDispatcher); popAsyncDispatcher(prevAsyncDispatcher); - if (workInProgress !== null) { - // This is a sync render, so we should have finished the whole tree. - throw new Error( - 'Cannot commit an incomplete root. This error is likely caused by a ' + - 'bug in React. Please file an issue.', - ); - } - if (__DEV__) { if (enableDebugTracing) { logRenderStopped(); @@ -2146,14 +2193,21 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) { markRenderStopped(); } - // Set this to null to indicate there's no in-progress render. - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; + if (workInProgress !== null) { + // Did not complete the tree. This can happen if something suspended in + // the shell. + } else { + // Normal case. We completed the whole tree. + + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; - // It's safe to process the queue now that the render phase is complete. - finishQueueingConcurrentUpdates(); + // It's safe to process the queue now that the render phase is complete. + finishQueueingConcurrentUpdates(); + } - return workInProgressRootExitStatus; + return exitStatus; } // The work loop is an extremely hot path. Tell Closure not to inline it. @@ -2199,9 +2253,7 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) { // // If we were previously in prerendering mode, check if we received any new // data during an interleaved event. - if (workInProgressRootIsPrerendering) { - workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); - } + workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); } if (__DEV__) { @@ -3753,6 +3805,9 @@ function pingSuspendedRoot( // the logic of whether or not a root suspends once it completes. // TODO: If we're rendering sync either due to Sync, Batched or expired, // we should probably never restart. + // TODO: Attach different listeners depending on whether the listener was + // attached during prerendering. Prerender pings should not interrupt + // normal renders. // If we're suspended with delay, or if it's a retry, we'll always suspend // so we can always restart. diff --git a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js index fd03ba7310f83..8ca142cb50517 100644 --- a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js +++ b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js @@ -420,6 +420,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); @@ -459,6 +463,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); @@ -533,6 +541,10 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', + + ...(gate('enableSiblingPrerendering') + ? ['Suspend! [Loading...]', 'Suspend! [Final]'] + : []), ]); expect(root).toMatchRenderedOutput(null); diff --git a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js index 37d907b0fdc65..235e8df2201de 100644 --- a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js @@ -479,4 +479,75 @@ describe('ReactSiblingPrerendering', () => { assertLog([]); }, ); + + it( + 'when a synchronous update suspends outside a boundary, the resulting' + + 'prerender is concurrent', + async () => { + function App() { + return ( + <> + + + + + + + ); + } + + const root = ReactNoop.createRoot(); + // Mount the root synchronously + ReactNoop.flushSync(() => root.render()); + + // Synchronously render everything until we suspend in the shell + assertLog(['A', 'B', 'Suspend! [Async]']); + + if (gate('enableSiblingPrerendering')) { + // The rest of the siblings begin to prerender concurrently. Notice + // that we don't unwind here; we pick up where we left off above. + await waitFor(['C']); + await waitFor(['D']); + } + + assertLog([]); + expect(root).toMatchRenderedOutput(null); + + await resolveText('Async'); + assertLog(['A', 'B', 'Async', 'C', 'D']); + expect(root).toMatchRenderedOutput('ABAsyncCD'); + }, + ); + + it('restart a suspended sync render if something suspends while prerendering the siblings', async () => { + function App() { + return ( + <> + + + + + + + ); + } + + const root = ReactNoop.createRoot(); + // Mount the root synchronously + ReactNoop.flushSync(() => root.render()); + + // Synchronously render everything until we suspend in the shell + assertLog(['A', 'B', 'Suspend! [Async]']); + + if (gate('enableSiblingPrerendering')) { + // The rest of the siblings begin to prerender concurrently + await waitFor(['C']); + } + + // While we're prerendering, Async resolves. We should unwind and + // start over, rather than continue prerendering D. + await resolveText('Async'); + assertLog(['A', 'B', 'Async', 'C', 'D']); + expect(root).toMatchRenderedOutput('ABAsyncCD'); + }); }); From 778e1ed2e5ec22d4bac48e14167d3b4a6b28e8b8 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Thu, 26 Sep 2024 00:20:03 +0200 Subject: [PATCH 194/426] [Fiber] Fix missing render times when we cancel a pending commit (#31065) --- packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js | 2 +- packages/react-reconciler/src/ReactFiberWorkLoop.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index d46f61035b8d4..af53a2a6acf47 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3401,7 +3401,7 @@ export function suspendResource( } } -export function waitForCommitToBeReady(): null | (Function => Function) { +export function waitForCommitToBeReady(): null | ((() => void) => () => void) { if (suspendedState === null) { throw new Error( 'Internal React Error: suspendedState null when it was expected to exists. Please report this as a React bug.', diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 5206caa5c0f76..ff50ff6973d1e 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -1308,6 +1308,8 @@ function commitRootWhenReady( updatedLanes, suspendedRetryLanes, SUSPENDED_COMMIT, + completedRenderStartTime, + completedRenderEndTime, ), ); const didAttemptEntireTree = !didSkipSuspendedSiblings; @@ -3001,8 +3003,6 @@ function commitRoot( ReactSharedInternals.T = prevTransition; setCurrentUpdatePriority(previousUpdateLanePriority); } - - return null; } function commitRootImpl( From d66fa02a303fc53d901bdb0d7bbdaec3e6774b19 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 26 Sep 2024 10:17:16 +0100 Subject: [PATCH 195/426] fix: use public instance in Fiber renderer and expose it from getInspectorDataForViewAtPoint (#31068) React DevTools no longer operates with just Fibers, it now builds its own Shadow Tree, which represents the tree on the Host (Fabric on Native, DOM on Web). We have to keep track of public instances for a select-to-inspect feature. We've recently changed this logic in https://github.com/facebook/react/pull/30831, and looks like we've been incorrectly getting a public instance for Fabric case. Not only this, turns out that all `getInspectorData...` APIs are returning Fibers, and not public instances. I have to expose it, so that React DevTools can correctly identify the element, which was selected. Changes for React Native are in [D63421463](https://www.internalfb.com/diff/D63421463) --- .../src/backend/fiber/renderer.js | 28 ++++++++++++++----- .../src/ReactNativeFiberInspector.js | 4 +++ .../src/ReactNativeTypes.js | 1 + 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index d93e713911561..22a7afcc4c632 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -763,16 +763,30 @@ const hostResourceToDevToolsInstanceMap: Map< Set, > = new Map(); +// Ideally, this should be injected from Reconciler config function getPublicInstance(instance: HostInstance): HostInstance { // Typically the PublicInstance and HostInstance is the same thing but not in Fabric. // So we need to detect this and use that as the public instance. - return typeof instance === 'object' && - instance !== null && - typeof instance.canonical === 'object' - ? (instance.canonical: any) - : typeof instance._nativeTag === 'number' - ? instance._nativeTag - : instance; + + // React Native. Modern. Fabric. + if (typeof instance === 'object' && instance !== null) { + if (typeof instance.canonical === 'object' && instance.canonical !== null) { + if ( + typeof instance.canonical.publicInstance === 'object' && + instance.canonical.publicInstance !== null + ) { + return instance.canonical.publicInstance; + } + } + + // React Native. Legacy. Paper. + if (typeof instance._nativeTag === 'number') { + return instance._nativeTag; + } + } + + // React Web. Usually a DOM element. + return instance; } function aquireHostInstance( diff --git a/packages/react-native-renderer/src/ReactNativeFiberInspector.js b/packages/react-native-renderer/src/ReactNativeFiberInspector.js index b0859471c463e..d0423f1d48cfa 100644 --- a/packages/react-native-renderer/src/ReactNativeFiberInspector.js +++ b/packages/react-native-renderer/src/ReactNativeFiberInspector.js @@ -209,6 +209,8 @@ function getInspectorDataForViewAtPoint( closestInstance = internalInstanceHandle.stateNode.canonical.internalInstanceHandle; + const closestPublicInstance = + internalInstanceHandle.stateNode.canonical.publicInstance; // Note: this is deprecated and we want to remove it ASAP. Keeping it here for React DevTools compatibility for now. const nativeViewTag = @@ -224,6 +226,7 @@ function getInspectorDataForViewAtPoint( pointerY: locationY, frame: {left: pageX, top: pageY, width, height}, touchedViewTag: nativeViewTag, + closestPublicInstance, }); }, ); @@ -243,6 +246,7 @@ function getInspectorDataForViewAtPoint( pointerY: locationY, frame: {left, top, width, height}, touchedViewTag: nativeViewTag, + closestPublicInstance: nativeViewTag, }); }, ); diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 000ea0d0f766d..9692a1256acff 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -179,6 +179,7 @@ export type TouchedViewDataAtPoint = $ReadOnly<{ width: number, height: number, }>, + closestPublicInstance?: PublicInstance, ...InspectorData, }>; From f8024b0686c87634b233262e8a05e4a37a292e87 Mon Sep 17 00:00:00 2001 From: Edmond Chui <1967998+EdmondChuiHW@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:39:28 +0100 Subject: [PATCH 196/426] refactor: allow custom impl of backend realod-to-profile support check (#31048) ## Summary In preparation to support reload-to-profile in Fusebox (#31021), we need a way to check capability of different backends, e.g. web vs React Native. ## How did you test this change? * Default, e.g. existing web impl = no-op * Custom impl: is called --- packages/react-devtools-core/src/backend.js | 18 +++++- .../src/contentScripts/backendManager.js | 3 +- packages/react-devtools-inline/src/backend.js | 3 +- .../src/backend/agent.js | 16 ++---- .../src/backend/index.js | 5 ++ packages/react-devtools-shared/src/bridge.js | 3 +- .../src/devtools/store.js | 56 +++++-------------- packages/react-devtools-shared/src/utils.js | 13 +++++ 8 files changed, 57 insertions(+), 60 deletions(-) diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index 1f2055832a3dd..dfc3db15138c6 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -13,7 +13,10 @@ import {installHook} from 'react-devtools-shared/src/hook'; import {initBackend} from 'react-devtools-shared/src/backend'; import {__DEBUG__} from 'react-devtools-shared/src/constants'; import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; -import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils'; +import { + getDefaultComponentFilters, + getIsReloadAndProfileSupported, +} from 'react-devtools-shared/src/utils'; import type {BackendBridge} from 'react-devtools-shared/src/bridge'; import type { @@ -36,6 +39,7 @@ type ConnectOptions = { isAppActive?: () => boolean, websocket?: ?WebSocket, onSettingsUpdated?: (settings: $ReadOnly) => void, + isReloadAndProfileSupported?: boolean, }; let savedComponentFilters: Array = @@ -77,6 +81,7 @@ export function connectToDevTools(options: ?ConnectOptions) { retryConnectionDelay = 2000, isAppActive = () => true, onSettingsUpdated, + isReloadAndProfileSupported = getIsReloadAndProfileSupported(), } = options || {}; const protocol = useHttps ? 'wss' : 'ws'; @@ -184,7 +189,7 @@ export function connectToDevTools(options: ?ConnectOptions) { hook.emit('shutdown'); }); - initBackend(hook, agent, window); + initBackend(hook, agent, window, isReloadAndProfileSupported); // Setup React Native style editor if the environment supports it. if (resolveRNStyle != null || hook.resolveRNStyle != null) { @@ -309,6 +314,7 @@ type ConnectWithCustomMessagingOptions = { nativeStyleEditorValidAttributes?: $ReadOnlyArray, resolveRNStyle?: ResolveNativeStyle, onSettingsUpdated?: (settings: $ReadOnly) => void, + isReloadAndProfileSupported?: boolean, }; export function connectWithCustomMessagingProtocol({ @@ -318,6 +324,7 @@ export function connectWithCustomMessagingProtocol({ nativeStyleEditorValidAttributes, resolveRNStyle, onSettingsUpdated, + isReloadAndProfileSupported = getIsReloadAndProfileSupported(), }: ConnectWithCustomMessagingOptions): Function { const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook == null) { @@ -368,7 +375,12 @@ export function connectWithCustomMessagingProtocol({ hook.emit('shutdown'); }); - const unsubscribeBackend = initBackend(hook, agent, window); + const unsubscribeBackend = initBackend( + hook, + agent, + window, + isReloadAndProfileSupported, + ); const nativeStyleResolver: ResolveNativeStyle | void = resolveRNStyle || hook.resolveRNStyle; diff --git a/packages/react-devtools-extensions/src/contentScripts/backendManager.js b/packages/react-devtools-extensions/src/contentScripts/backendManager.js index 36a2ab19aa411..9d3ec414330ed 100644 --- a/packages/react-devtools-extensions/src/contentScripts/backendManager.js +++ b/packages/react-devtools-extensions/src/contentScripts/backendManager.js @@ -13,6 +13,7 @@ import type { } from 'react-devtools-shared/src/backend/types'; import {hasAssignedBackend} from 'react-devtools-shared/src/backend/utils'; import {COMPACT_VERSION_NAME} from 'react-devtools-extensions/src/utils'; +import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils'; let welcomeHasInitialized = false; @@ -140,7 +141,7 @@ function activateBackend(version: string, hook: DevToolsHook) { hook.emit('shutdown'); }); - initBackend(hook, agent, window); + initBackend(hook, agent, window, getIsReloadAndProfileSupported()); // Setup React Native style editor if a renderer like react-native-web has injected it. if (typeof setupNativeStyleEditor === 'function' && hook.resolveRNStyle) { diff --git a/packages/react-devtools-inline/src/backend.js b/packages/react-devtools-inline/src/backend.js index fca1535c4e5ba..41af7809be0b1 100644 --- a/packages/react-devtools-inline/src/backend.js +++ b/packages/react-devtools-inline/src/backend.js @@ -8,6 +8,7 @@ import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyl import type {BackendBridge} from 'react-devtools-shared/src/bridge'; import type {Wall} from 'react-devtools-shared/src/frontend/types'; +import {getIsReloadAndProfileSupported} from 'react-devtools-shared/src/utils'; function startActivation(contentWindow: any, bridge: BackendBridge) { const onSavedPreferences = (data: $FlowFixMe) => { @@ -66,7 +67,7 @@ function finishActivation(contentWindow: any, bridge: BackendBridge) { const hook = contentWindow.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook) { - initBackend(hook, agent, contentWindow); + initBackend(hook, agent, contentWindow, getIsReloadAndProfileSupported()); // Setup React Native style editor if a renderer like react-native-web has injected it. if (hook.resolveRNStyle) { diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index e55e8a6d41e2b..a1e96bfcdeb39 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -38,7 +38,7 @@ import type { DevToolsHookSettings, } from './types'; import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types'; -import {isSynchronousXHRSupported, isReactNativeEnvironment} from './utils'; +import {isReactNativeEnvironment} from './utils'; const debug = (methodName: string, ...args: Array) => { if (__DEBUG__) { @@ -242,16 +242,6 @@ export default class Agent extends EventEmitter<{ if (this._isProfiling) { bridge.send('profilingStatus', true); } - - // Notify the frontend if the backend supports the Storage API (e.g. localStorage). - // If not, features like reload-and-profile will not work correctly and must be disabled. - let isBackendStorageAPISupported = false; - try { - localStorage.getItem('test'); - isBackendStorageAPISupported = true; - } catch (error) {} - bridge.send('isBackendStorageAPISupported', isBackendStorageAPISupported); - bridge.send('isSynchronousXHRSupported', isSynchronousXHRSupported()); } get rendererInterfaces(): {[key: RendererID]: RendererInterface, ...} { @@ -675,6 +665,10 @@ export default class Agent extends EventEmitter<{ } }; + onReloadAndProfileSupportedByHost: () => void = () => { + this._bridge.send('isReloadAndProfileSupportedByBackend', true); + }; + reloadAndProfile: (recordChangeDescriptions: boolean) => void = recordChangeDescriptions => { sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true'); diff --git a/packages/react-devtools-shared/src/backend/index.js b/packages/react-devtools-shared/src/backend/index.js index 5893424b394c8..86714b7f61476 100644 --- a/packages/react-devtools-shared/src/backend/index.js +++ b/packages/react-devtools-shared/src/backend/index.js @@ -17,6 +17,7 @@ export function initBackend( hook: DevToolsHook, agent: Agent, global: Object, + isReloadAndProfileSupported: boolean, ): () => void { if (hook == null) { // DevTools didn't get injected into this page (maybe b'c of the contentType). @@ -94,6 +95,10 @@ export function initBackend( } }); + if (isReloadAndProfileSupported) { + agent.onReloadAndProfileSupportedByHost(); + } + return () => { subs.forEach(fn => fn()); }; diff --git a/packages/react-devtools-shared/src/bridge.js b/packages/react-devtools-shared/src/bridge.js index fcf9b2d21e88d..dde6e7c3ffff8 100644 --- a/packages/react-devtools-shared/src/bridge.js +++ b/packages/react-devtools-shared/src/bridge.js @@ -181,8 +181,7 @@ export type BackendEvents = { fastRefreshScheduled: [], getSavedPreferences: [], inspectedElement: [InspectedElementPayload], - isBackendStorageAPISupported: [boolean], - isSynchronousXHRSupported: [boolean], + isReloadAndProfileSupportedByBackend: [boolean], operations: [Array], ownersList: [OwnersList], overrideComponentFilters: [Array], diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js index b1544126d8d6e..8af997d9287ef 100644 --- a/packages/react-devtools-shared/src/devtools/store.js +++ b/packages/react-devtools-shared/src/devtools/store.js @@ -138,16 +138,6 @@ export default class Store extends EventEmitter<{ // Should the React Native style editor panel be shown? _isNativeStyleEditorSupported: boolean = false; - // Can the backend use the Storage API (e.g. localStorage)? - // If not, features like reload-and-profile will not work correctly and must be disabled. - _isBackendStorageAPISupported: boolean = false; - - // Can DevTools use sync XHR requests? - // If not, features like reload-and-profile will not work correctly and must be disabled. - // This current limitation applies only to web extension builds - // and will need to be reconsidered in the future if we add support for reload to React Native. - _isSynchronousXHRSupported: boolean = false; - _nativeStyleEditorValidAttributes: $ReadOnlyArray | null = null; // Older backends don't support an explicit bridge protocol, @@ -178,10 +168,12 @@ export default class Store extends EventEmitter<{ // These options may be initially set by a configuration option when constructing the Store. _supportsInspectMatchingDOMElement: boolean = false; _supportsClickToInspect: boolean = false; - _supportsReloadAndProfile: boolean = false; _supportsTimeline: boolean = false; _supportsTraceUpdates: boolean = false; + _isReloadAndProfileFrontendSupported: boolean = false; + _isReloadAndProfileBackendSupported: boolean = false; + // These options default to false but may be updated as roots are added and removed. _rootSupportsBasicProfiling: boolean = false; _rootSupportsTimelineProfiling: boolean = false; @@ -234,7 +226,7 @@ export default class Store extends EventEmitter<{ this._supportsClickToInspect = true; } if (supportsReloadAndProfile) { - this._supportsReloadAndProfile = true; + this._isReloadAndProfileFrontendSupported = true; } if (supportsTimeline) { this._supportsTimeline = true; @@ -255,17 +247,13 @@ export default class Store extends EventEmitter<{ ); bridge.addListener('shutdown', this.onBridgeShutdown); bridge.addListener( - 'isBackendStorageAPISupported', - this.onBackendStorageAPISupported, + 'isReloadAndProfileSupportedByBackend', + this.onBackendReloadAndProfileSupported, ); bridge.addListener( 'isNativeStyleEditorSupported', this.onBridgeNativeStyleEditorSupported, ); - bridge.addListener( - 'isSynchronousXHRSupported', - this.onBridgeSynchronousXHRSupported, - ); bridge.addListener( 'unsupportedRendererVersion', this.onBridgeUnsupportedRendererVersion, @@ -469,13 +457,9 @@ export default class Store extends EventEmitter<{ } get supportsReloadAndProfile(): boolean { - // Does the DevTools shell support reloading and eagerly injecting the renderer interface? - // And if so, can the backend use the localStorage API and sync XHR? - // All of these are currently required for the reload-and-profile feature to work. return ( - this._supportsReloadAndProfile && - this._isBackendStorageAPISupported && - this._isSynchronousXHRSupported + this._isReloadAndProfileFrontendSupported && + this._isReloadAndProfileBackendSupported ); } @@ -1433,17 +1417,13 @@ export default class Store extends EventEmitter<{ ); bridge.removeListener('shutdown', this.onBridgeShutdown); bridge.removeListener( - 'isBackendStorageAPISupported', - this.onBackendStorageAPISupported, + 'isReloadAndProfileSupportedByBackend', + this.onBackendReloadAndProfileSupported, ); bridge.removeListener( 'isNativeStyleEditorSupported', this.onBridgeNativeStyleEditorSupported, ); - bridge.removeListener( - 'isSynchronousXHRSupported', - this.onBridgeSynchronousXHRSupported, - ); bridge.removeListener( 'unsupportedRendererVersion', this.onBridgeUnsupportedRendererVersion, @@ -1458,18 +1438,10 @@ export default class Store extends EventEmitter<{ } }; - onBackendStorageAPISupported: ( - isBackendStorageAPISupported: boolean, - ) => void = isBackendStorageAPISupported => { - this._isBackendStorageAPISupported = isBackendStorageAPISupported; - - this.emit('supportsReloadAndProfile'); - }; - - onBridgeSynchronousXHRSupported: ( - isSynchronousXHRSupported: boolean, - ) => void = isSynchronousXHRSupported => { - this._isSynchronousXHRSupported = isSynchronousXHRSupported; + onBackendReloadAndProfileSupported: ( + isReloadAndProfileSupported: boolean, + ) => void = isReloadAndProfileSupported => { + this._isReloadAndProfileBackendSupported = isReloadAndProfileSupported; this.emit('supportsReloadAndProfile'); }; diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index e24414812c5b3..a9ebeaaa129da 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -61,6 +61,7 @@ import type { LRUCache, } from 'react-devtools-shared/src/frontend/types'; import type {SerializedElement as SerializedElementBackend} from 'react-devtools-shared/src/backend/types'; +import {isSynchronousXHRSupported} from './backend/utils'; // $FlowFixMe[method-unbinding] const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -965,3 +966,15 @@ export function backendToFrontendSerializedElementMapper( export function normalizeUrl(url: string): string { return url.replace('/./', '/'); } + +export function getIsReloadAndProfileSupported(): boolean { + // Notify the frontend if the backend supports the Storage API (e.g. localStorage). + // If not, features like reload-and-profile will not work correctly and must be disabled. + let isBackendStorageAPISupported = false; + try { + localStorage.getItem('test'); + isBackendStorageAPISupported = true; + } catch (error) {} + + return isBackendStorageAPISupported && isSynchronousXHRSupported(); +} From 9927ab238bde0a2dcadc881e56d6a87208e93e45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:45:02 -0400 Subject: [PATCH 197/426] Bump rollup from 4.13.2 to 4.22.4 in /compiler (#31039) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [rollup](https://github.com/rollup/rollup) from 4.13.2 to 4.22.4.
Release notes

Sourced from rollup's releases.

v4.22.4

4.22.4

2024-09-21

Bug Fixes

  • Fix a vulnerability in generated code that affects IIFE, UMD and CJS bundles when run in a browser context (#5671)

Pull Requests

v4.22.3

4.22.3

2024-09-21

Bug Fixes

  • Ensure that mutations in modules without side effects are observed while properly handling transitive dependencies (#5669)

Pull Requests

v4.22.2

4.22.2

2024-09-20

Bug Fixes

  • Revert fix for side effect free modules until other issues are investigated (#5667)

Pull Requests

v4.22.1

4.22.1

2024-09-20

Bug Fixes

  • Revert #5644 "stable chunk hashes" while issues are being investigated

Pull Requests

... (truncated)

Changelog

Sourced from rollup's changelog.

4.22.4

2024-09-21

Bug Fixes

  • Fix a vulnerability in generated code that affects IIFE, UMD and CJS bundles when run in a browser context (#5671)

Pull Requests

4.22.3

2024-09-21

Bug Fixes

  • Ensure that mutations in modules without side effects are observed while properly handling transitive dependencies (#5669)

Pull Requests

4.22.2

2024-09-20

Bug Fixes

  • Revert fix for side effect free modules until other issues are investigated (#5667)

Pull Requests

4.22.1

2024-09-20

Bug Fixes

  • Revert #5644 "stable chunk hashes" while issues are being investigated

Pull Requests

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rollup&package-manager=npm_and_yarn&previous-version=4.13.2&new-version=4.22.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- compiler/package.json | 2 +- compiler/yarn.lock | 199 +++++++++++++++++++++--------------------- 2 files changed, 101 insertions(+), 100 deletions(-) diff --git a/compiler/package.json b/compiler/package.json index 3adb2d279f159..2d898b1305b9f 100644 --- a/compiler/package.json +++ b/compiler/package.json @@ -43,7 +43,7 @@ "prettier": "^3.3.3", "prettier-plugin-hermes-parser": "^0.23.0", "prompt-promise": "^1.0.3", - "rollup": "^4.13.2", + "rollup": "^4.22.4", "rollup-plugin-banner2": "^1.2.3", "rollup-plugin-prettier": "^4.1.1", "typescript": "^5.4.3", diff --git a/compiler/yarn.lock b/compiler/yarn.lock index 002e43a408bfb..f599318e2e4bc 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -2762,80 +2762,85 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.2.tgz#fbf098f49d96a8cac9056f22f5fd80906ef3af85" - integrity sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g== - -"@rollup/rollup-android-arm64@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.2.tgz#0d2448251040fce19a98eee505dff5b3c8ec9b98" - integrity sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ== - -"@rollup/rollup-darwin-arm64@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.2.tgz#78db4d4da5b1b84c22adbe25c8a4961b3f22d3af" - integrity sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA== - -"@rollup/rollup-darwin-x64@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.2.tgz#fcc05af54379f8ee5c7e954987d4514c6fd0fb42" - integrity sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A== - -"@rollup/rollup-linux-arm-gnueabihf@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.2.tgz#2ce200efa1ef4a56ee2af7b453edc74a259d7d31" - integrity sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ== - -"@rollup/rollup-linux-arm64-gnu@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.2.tgz#5a24aac882bff9abfda3f45f6f1db2166c342a4a" - integrity sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ== - -"@rollup/rollup-linux-arm64-musl@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.2.tgz#f1fb4c6f961d3f3397231a99e621d199200e4ea9" - integrity sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA== - -"@rollup/rollup-linux-powerpc64le-gnu@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.13.2.tgz#46b2463d94ac3af3e0f7a2947b695397bc13b755" - integrity sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ== - -"@rollup/rollup-linux-riscv64-gnu@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.2.tgz#47b932ee59a5395a3a341b0493e361d9e6032cf2" - integrity sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw== - -"@rollup/rollup-linux-s390x-gnu@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.2.tgz#8e14a1b3c3b9a4440c70a9c1ba12d32aa21f9712" - integrity sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg== - -"@rollup/rollup-linux-x64-gnu@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.2.tgz#270e939194b66df77bcb33dd9a5ddf7784bd7997" - integrity sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A== - -"@rollup/rollup-linux-x64-musl@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.2.tgz#e8dd0f3c2046acbda2934490b36552e856a3bc6a" - integrity sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA== - -"@rollup/rollup-win32-arm64-msvc@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.2.tgz#f8b65a4a7e7a6b383e7b14439129b2f474ff123c" - integrity sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA== - -"@rollup/rollup-win32-ia32-msvc@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.2.tgz#bc1c5a4fbc4337d6cb15da80a4de95fd53ab3573" - integrity sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw== - -"@rollup/rollup-win32-x64-msvc@4.13.2": - version "4.13.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.2.tgz#851959c4c1c3c6647aba1f388198c8243aed6917" - integrity sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ== +"@rollup/rollup-android-arm-eabi@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz#8b613b9725e8f9479d142970b106b6ae878610d5" + integrity sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w== + +"@rollup/rollup-android-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz#654ca1049189132ff602bfcf8df14c18da1f15fb" + integrity sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA== + +"@rollup/rollup-darwin-arm64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz#6d241d099d1518ef0c2205d96b3fa52e0fe1954b" + integrity sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q== + +"@rollup/rollup-darwin-x64@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz#42bd19d292a57ee11734c980c4650de26b457791" + integrity sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw== + +"@rollup/rollup-linux-arm-gnueabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz#f23555ee3d8fe941c5c5fd458cd22b65eb1c2232" + integrity sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ== + +"@rollup/rollup-linux-arm-musleabihf@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz#f3bbd1ae2420f5539d40ac1fde2b38da67779baa" + integrity sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg== + +"@rollup/rollup-linux-arm64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz#7abe900120113e08a1f90afb84c7c28774054d15" + integrity sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw== + +"@rollup/rollup-linux-arm64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz#9e655285c8175cd44f57d6a1e8e5dedfbba1d820" + integrity sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz#9a79ae6c9e9d8fe83d49e2712ecf4302db5bef5e" + integrity sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg== + +"@rollup/rollup-linux-riscv64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz#67ac70eca4ace8e2942fabca95164e8874ab8128" + integrity sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA== + +"@rollup/rollup-linux-s390x-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz#9f883a7440f51a22ed7f99e1d070bd84ea5005fc" + integrity sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q== + +"@rollup/rollup-linux-x64-gnu@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz#70116ae6c577fe367f58559e2cffb5641a1dd9d0" + integrity sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg== + +"@rollup/rollup-linux-x64-musl@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz#f473f88219feb07b0b98b53a7923be716d1d182f" + integrity sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g== + +"@rollup/rollup-win32-arm64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz#4349482d17f5d1c58604d1c8900540d676f420e0" + integrity sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw== + +"@rollup/rollup-win32-ia32-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz#a6fc39a15db618040ec3c2a24c1e26cb5f4d7422" + integrity sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g== + +"@rollup/rollup-win32-x64-msvc@4.22.4": + version "4.22.4" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz#3dd5d53e900df2a40841882c02e56f866c04d202" + integrity sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q== "@rushstack/eslint-patch@^1.3.3": version "1.5.1" @@ -3013,12 +3018,7 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" - integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== - -"@types/estree@1.0.5": +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -8896,28 +8896,29 @@ rollup-plugin-prettier@^4.1.1: lodash.omitby "4.6.0" magic-string "0.30.5" -rollup@^4.13.2: - version "4.13.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.2.tgz#ac57d2dc48e8f5562f5a6daadb9caee590069262" - integrity sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g== +rollup@^4.22.4: + version "4.22.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.22.4.tgz#4135a6446671cd2a2453e1ad42a45d5973ec3a0f" + integrity sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A== dependencies: "@types/estree" "1.0.5" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.13.2" - "@rollup/rollup-android-arm64" "4.13.2" - "@rollup/rollup-darwin-arm64" "4.13.2" - "@rollup/rollup-darwin-x64" "4.13.2" - "@rollup/rollup-linux-arm-gnueabihf" "4.13.2" - "@rollup/rollup-linux-arm64-gnu" "4.13.2" - "@rollup/rollup-linux-arm64-musl" "4.13.2" - "@rollup/rollup-linux-powerpc64le-gnu" "4.13.2" - "@rollup/rollup-linux-riscv64-gnu" "4.13.2" - "@rollup/rollup-linux-s390x-gnu" "4.13.2" - "@rollup/rollup-linux-x64-gnu" "4.13.2" - "@rollup/rollup-linux-x64-musl" "4.13.2" - "@rollup/rollup-win32-arm64-msvc" "4.13.2" - "@rollup/rollup-win32-ia32-msvc" "4.13.2" - "@rollup/rollup-win32-x64-msvc" "4.13.2" + "@rollup/rollup-android-arm-eabi" "4.22.4" + "@rollup/rollup-android-arm64" "4.22.4" + "@rollup/rollup-darwin-arm64" "4.22.4" + "@rollup/rollup-darwin-x64" "4.22.4" + "@rollup/rollup-linux-arm-gnueabihf" "4.22.4" + "@rollup/rollup-linux-arm-musleabihf" "4.22.4" + "@rollup/rollup-linux-arm64-gnu" "4.22.4" + "@rollup/rollup-linux-arm64-musl" "4.22.4" + "@rollup/rollup-linux-powerpc64le-gnu" "4.22.4" + "@rollup/rollup-linux-riscv64-gnu" "4.22.4" + "@rollup/rollup-linux-s390x-gnu" "4.22.4" + "@rollup/rollup-linux-x64-gnu" "4.22.4" + "@rollup/rollup-linux-x64-musl" "4.22.4" + "@rollup/rollup-win32-arm64-msvc" "4.22.4" + "@rollup/rollup-win32-ia32-msvc" "4.22.4" + "@rollup/rollup-win32-x64-msvc" "4.22.4" fsevents "~2.3.2" rrweb-cssom@^0.6.0: From d0772d586650baa5cf5c676ab1092a075ffdf831 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:51:12 -0400 Subject: [PATCH 198/426] Bump axios from 1.7.1 to 1.7.4 in /compiler (#30694) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [axios](https://github.com/axios/axios) from 1.7.1 to 1.7.4.
Release notes

Sourced from axios's releases.

Release v1.7.4

Release notes:

Bug Fixes

Contributors to this release

Release v1.7.3

Release notes:

Bug Fixes

  • adapter: fix progress event emitting; (#6518) (e3c76fc)
  • fetch: fix withCredentials request config (#6505) (85d4d0e)
  • xhr: return original config on errors from XHR adapter (#6515) (8966ee7)

Contributors to this release

Release v1.7.2

Release notes:

Bug Fixes

Contributors to this release

Changelog

Sourced from axios's changelog.

1.7.4 (2024-08-13)

Bug Fixes

Contributors to this release

1.7.3 (2024-08-01)

Bug Fixes

  • adapter: fix progress event emitting; (#6518) (e3c76fc)
  • fetch: fix withCredentials request config (#6505) (85d4d0e)
  • xhr: return original config on errors from XHR adapter (#6515) (8966ee7)

Contributors to this release

1.7.2 (2024-05-21)

Bug Fixes

Contributors to this release

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=axios&package-manager=npm_and_yarn&previous-version=1.7.1&new-version=1.7.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- compiler/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/yarn.lock b/compiler/yarn.lock index f599318e2e4bc..76f33a20adeb8 100644 --- a/compiler/yarn.lock +++ b/compiler/yarn.lock @@ -3679,9 +3679,9 @@ axe-core@^4.6.2: integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g== axios@^1.6.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.1.tgz#522145622a09dfaf49359837db9649ff245a35b9" - integrity sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q== + version "1.7.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" + integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" From f04b8fc88e83c3cbe670bf6ec46d27cfcb3f52e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:56:10 -0400 Subject: [PATCH 199/426] Bump ws from 6.2.2 to 6.2.3 in /scripts/release (#30463) Bumps [ws](https://github.com/websockets/ws) from 6.2.2 to 6.2.3.
Release notes

Sourced from ws's releases.

6.2.3

Bug fixes

  • Backported e55e5106 to the 6.x release line (eeb76d31).
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ws&package-manager=npm_and_yarn&previous-version=6.2.2&new-version=6.2.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- scripts/release/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/release/yarn.lock b/scripts/release/yarn.lock index 4a68f9ac5d221..e5bdb7e5972f5 100644 --- a/scripts/release/yarn.lock +++ b/scripts/release/yarn.lock @@ -910,9 +910,9 @@ wrappy@1: integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= ws@^6.1.0: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" - integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + version "6.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee" + integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA== dependencies: async-limiter "~1.0.0" From f7aff7f15c451dc78eb967c726be4f612bcaf966 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:56:24 -0400 Subject: [PATCH 200/426] Bump express from 4.18.2 to 4.21.0 (#30980) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.21.0.
Release notes

Sourced from express's releases.

4.21.0

What's Changed

New Contributors

Full Changelog: https://github.com/expressjs/express/compare/4.20.0...4.21.0

4.20.0

What's Changed

Important

  • IMPORTANT: The default depth level for parsing URL-encoded data is now 32 (previously was Infinity)
  • Remove link renderization in html while using res.redirect

Other Changes

... (truncated)

Changelog

Sourced from express's changelog.

4.21.0 / 2024-09-11

  • Deprecate res.location("back") and res.redirect("back") magic string
  • deps: serve-static@1.16.2
    • includes send@0.19.0
  • deps: finalhandler@1.3.1
  • deps: qs@6.13.0

4.20.0 / 2024-09-10

  • deps: serve-static@0.16.0
    • Remove link renderization in html while redirecting
  • deps: send@0.19.0
    • Remove link renderization in html while redirecting
  • deps: body-parser@0.6.0
    • add depth option to customize the depth level in the parser
    • IMPORTANT: The default depth level for parsing URL-encoded data is now 32 (previously was Infinity)
  • Remove link renderization in html while using res.redirect
  • deps: path-to-regexp@0.1.10
    • Adds support for named matching groups in the routes using a regex
    • Adds backtracking protection to parameters without regexes defined
  • deps: encodeurl@~2.0.0
    • Removes encoding of \, |, and ^ to align better with URL spec
  • Deprecate passing options.maxAge and options.expires to res.clearCookie
    • Will be ignored in v5, clearCookie will set a cookie with an expires in the past to instruct clients to delete the cookie

4.19.2 / 2024-03-25

  • Improved fix for open redirect allow list bypass

4.19.1 / 2024-03-20

  • Allow passing non-strings to res.location with new encoding handling checks

4.19.0 / 2024-03-20

  • Prevent open redirect allow list bypass due to encodeurl
  • deps: cookie@0.6.0

4.18.3 / 2024-02-29

  • Fix routing requests without method
  • deps: body-parser@1.20.2
    • Fix strict json error message on Node.js 19+
    • deps: content-type@~1.0.5

... (truncated)

Commits
Maintainer changes

This version was pushed to npm by wesleytodd, a new releaser for express since your current version.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=express&package-manager=npm_and_yarn&previous-version=4.18.2&new-version=4.21.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 225 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 157 insertions(+), 68 deletions(-) diff --git a/yarn.lock b/yarn.lock index b23f0d92aebfc..c5dfb9e6c3738 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5031,21 +5031,21 @@ bluebird@~3.7: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" - content-type "~1.0.4" + content-type "~1.0.5" debug "2.6.9" depd "2.0.0" destroy "1.2.0" http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" + qs "6.13.0" + raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -5402,6 +5402,17 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -6052,6 +6063,11 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + convert-source-map@^1.1.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" @@ -6074,10 +6090,10 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== cookie@^0.3.1: version "0.3.1" @@ -6692,6 +6708,15 @@ defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" @@ -7052,6 +7077,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -7180,6 +7210,18 @@ es-abstract@^1.17.2, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-module-lexer@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527" @@ -7309,7 +7351,6 @@ eslint-plugin-no-unsanitized@4.0.2: "eslint-plugin-react-internal@link:./scripts/eslint-rules": version "0.0.0" - uid "" eslint-plugin-react@^6.7.1: version "6.10.3" @@ -7828,36 +7869,36 @@ expect@^29.7.0: jest-util "^29.7.0" express@^4.17.3: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.1" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -8219,13 +8260,13 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -8563,6 +8604,17 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -8895,6 +8947,13 @@ google-closure-compiler@^20230206.0.0: google-closure-compiler-osx "^20230206.0.0" google-closure-compiler-windows "^20230206.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + got@^11.1.4, got@^11.8.5: version "11.8.6" resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" @@ -9086,6 +9145,18 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" @@ -9106,6 +9177,11 @@ has-symbols@^1.0.2: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" @@ -11685,10 +11761,10 @@ meow@^3.3.0: redent "^1.0.0" trim-newlines "^1.0.0" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -12303,16 +12379,16 @@ object-inspect@^1.10.3: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + object-inspect@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== -object-inspect@^1.9.0: - version "1.12.3" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" - integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== - object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -12953,10 +13029,10 @@ path-scurry@^1.7.0: lru-cache "^9.1.1" minipass "^5.0.0 || ^6.0.2" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== path-type@^1.0.0: version "1.1.0" @@ -13573,12 +13649,12 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" query-string@^5.0.1: version "5.1.1" @@ -13658,10 +13734,10 @@ range-parser@^1.2.1, range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" http-errors "2.0.0" @@ -14593,10 +14669,10 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -14639,21 +14715,33 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -14757,14 +14845,15 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" From db320ea4d910d360ccb83850ccdbc464a77fc1c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:56:33 -0400 Subject: [PATCH 201/426] Bump rollup from 3.20.0 to 3.29.5 (#31072) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [rollup](https://github.com/rollup/rollup) from 3.20.0 to 3.29.5.
Release notes

Sourced from rollup's releases.

v3.29.4

3.29.4

2023-09-28

Bug Fixes

  • Fix static analysis when an exported function uses callbacks (#5158)

Pull Requests

v3.29.3

3.29.3

2023-09-24

Bug Fixes

  • Fix a bug where code was wrongly tree-shaken after mutating function parameters (#5153)

Pull Requests

  • #5145: docs: improve the docs repl appearance in the light mode (@​TrickyPi)
  • #5148: chore(deps): update dependency @​vue/eslint-config-typescript to v12 (@​renovate[bot])
  • #5149: chore(deps): lock file maintenance minor/patch updates (@​renovate[bot])
  • #5153: Fully deoptimize first level path when deoptimizing nested parameter paths (@​lukastaegert)

v3.29.2

3.29.2

2023-09-15

Bug Fixes

  • Export TreeshakingPreset type (#5131)

Pull Requests

v3.29.1

3.29.1

2023-09-10

Bug Fixes

... (truncated)

Changelog

Sourced from rollup's changelog.

rollup changelog

4.22.4

2024-09-21

Bug Fixes

  • Fix a vulnerability in generated code that affects IIFE, UMD and CJS bundles when run in a browser context (#5671)

Pull Requests

4.22.3

2024-09-21

Bug Fixes

  • Ensure that mutations in modules without side effects are observed while properly handling transitive dependencies (#5669)

Pull Requests

4.22.2

2024-09-20

Bug Fixes

  • Revert fix for side effect free modules until other issues are investigated (#5667)

Pull Requests

4.22.1

2024-09-20

Bug Fixes

  • Revert #5644 "stable chunk hashes" while issues are being investigated

Pull Requests

... (truncated)

Commits
  • dfd233d 3.29.5
  • 2ef77c0 Fix DOM Clobbering CVE
  • a6448b9 3.29.4
  • 4e92d60 Deoptimize all parameters when losing track of a function (#5158)
  • 801ffd1 3.29.3
  • 353e462 Fully deoptimize first level path when deoptimizing nested parameter paths (#...
  • a1a89e7 chore(deps): update dependency @​vue/eslint-config-typescript to v12 (#5148)
  • cc14f70 chore(deps): lock file maintenance minor/patch updates (#5149)
  • 1e8355b docs: improve the docs repl appearance in the light mode (#5145)
  • 5950fc8 Adapt branches in REPL workflow
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rollup&package-manager=npm_and_yarn&previous-version=3.20.0&new-version=3.29.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cae8499738d22..cffd0ba28b493 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "random-seed": "^0.3.0", "react-lifecycles-compat": "^3.0.4", "rimraf": "^3.0.0", - "rollup": "^3.17.1", + "rollup": "^3.29.5", "rollup-plugin-prettier": "^4.1.1", "rollup-plugin-strip-banner": "^3.0.0", "semver": "^7.1.1", diff --git a/yarn.lock b/yarn.lock index c5dfb9e6c3738..d52bc62f789d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14395,10 +14395,10 @@ rollup-pluginutils@2.8.2: dependencies: estree-walker "^0.6.1" -rollup@^3.17.1: - version "3.20.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.20.0.tgz#ce7bd88449a776b9f75bf4e35959e25fbd3f51b1" - integrity sha512-YsIfrk80NqUDrxrjWPXUa7PWvAfegZEXHuPsEZg58fGCdjL1I9C1i/NaG+L+27kxxwkrG/QEDEQc8s/ynXWWGQ== +rollup@^3.29.5: + version "3.29.5" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" + integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== optionalDependencies: fsevents "~2.3.2" From 64be7b4dccb7b19404b94afdfab955e1c73796df Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 09:55:36 -0400 Subject: [PATCH 202/426] [ci] Fix missing values during manual workflow dispatch It seems like the github.event.workflow_run payload is only populated for non manual runs of the workflow, so this would crash the manual dispatch Test plan: https://github.com/facebook/react/actions/runs/11017512571 completes ghstack-source-id: fce02b17f85ac4762de0561764785882e767c872 Pull Request resolved: https://github.com/facebook/react/pull/31045 --- .../workflows/runtime_commit_artifacts.yml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index 9710fa4eed9ff..c6d5f7e7b499d 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -82,7 +82,7 @@ jobs: working-directory: scripts/release - name: Download artifacts for base revision run: | - GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.event.workflow_run.head_sha }} + GH_TOKEN=${{ github.token }} scripts/release/download-experimental-build.js --commit=${{ inputs.commit_sha || github.sha }} - name: Display structure of build run: ls -R build - name: Strip @license from eslint plugin and react-refresh @@ -145,9 +145,9 @@ jobs: ls -R ./compiled-rn - name: Add REVISION files run: | - echo ${{ github.event.workflow_run.head_sha }} >> ./compiled/facebook-www/REVISION + echo ${{ github.sha }} >> ./compiled/facebook-www/REVISION cp ./compiled/facebook-www/REVISION ./compiled/facebook-www/REVISION_TRANSFORMS - echo ${{ github.event.workflow_run.head_sha}} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION + echo ${{ github.sha}} >> ./compiled-rn/facebook-fbsource/xplat/js/react-native-github/Libraries/Renderer/REVISION - name: "Get current version string" id: get_current_version run: | @@ -245,12 +245,12 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: | - ${{ github.event.workflow_run.head_commit.message }} + ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} - DiffTrain build for [${{ github.event.workflow_run.head_sha }}](https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha }}) + DiffTrain build for [${{ github.sha }}](https://github.com/facebook/react/commit/${{ github.sha }}) branch: builds/facebook-www - commit_user_name: ${{ github.event.workflow_run.triggering_actor.login }} - commit_user_email: ${{ github.event.workflow_run.triggering_actor.email || format('{0}@users.noreply.github.com', github.event.workflow_run.triggering_actor.login) }} + commit_user_name: ${{ github.triggering_actor }} + commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }} create_branch: true commit_fbsource_artifacts: @@ -412,10 +412,10 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: | - ${{ github.event.workflow_run.head_commit.message }} + ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} - DiffTrain build for commit https://github.com/facebook/react/commit/${{ github.event.workflow_run.head_sha }}. + DiffTrain build for commit https://github.com/facebook/react/commit/${{ github.sha }}. branch: builds/facebook-fbsource - commit_user_name: ${{ github.event.workflow_run.triggering_actor.login }} - commit_user_email: ${{ github.event.workflow_run.triggering_actor.email || format('{0}@users.noreply.github.com', github.event.workflow_run.triggering_actor.login) }} + commit_user_name: ${{ github.triggering_actor }} + commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }} create_branch: true From c900ee0cce3be7703f5abd944611bfe932d5a530 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 09:55:37 -0400 Subject: [PATCH 203/426] [ez] Make commit sha clickable for fbsource ghstack-source-id: 1307b9a83a8613c08f11be5397ab45719df00992 Pull Request resolved: https://github.com/facebook/react/pull/31046 --- .github/workflows/runtime_commit_artifacts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index c6d5f7e7b499d..e562b34cea0f8 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -414,7 +414,7 @@ jobs: commit_message: | ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} - DiffTrain build for commit https://github.com/facebook/react/commit/${{ github.sha }}. + DiffTrain build for [${{ github.sha }}](https://github.com/facebook/react/commit/${{ github.sha }}) branch: builds/facebook-fbsource commit_user_name: ${{ github.triggering_actor }} commit_user_email: ${{ format('{0}@users.noreply.github.com', github.triggering_actor) }} From b7f74f39d8979307354f0d5c8a5daa8456ea4f2f Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 09:55:39 -0400 Subject: [PATCH 204/426] [ez] Update deprecated action ghstack-source-id: 991b314fd610bcbca68df52149866b2c6d8e6799 Pull Request resolved: https://github.com/facebook/react/pull/31047 --- .github/workflows/runtime_commit_artifacts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index e562b34cea0f8..6ff1bdb5a638d 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -242,7 +242,7 @@ jobs: git status -u - name: Commit changes to branch if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: | ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} @@ -409,7 +409,7 @@ jobs: git status - name: Commit changes to branch if: inputs.force == true || steps.check_should_commit.outputs.should_commit == 'true' - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: | ${{ github.event.workflow_run.head_commit.message || 'No commit message' }} From 0e9ccde185d0556f8d672689d937b5423476beff Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 10:22:37 -0400 Subject: [PATCH 205/426] [dependabot] Remove stale directories from config ghstack-source-id: 570399bc77529bf9fb005149cfd20ba59405b2bc Pull Request resolved: https://github.com/facebook/react/pull/31073 --- .github/dependabot.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b436c26c50c29..4c591dbca1520 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -40,11 +40,6 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/fiber-triangle" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - package-ecosystem: "npm" directory: "/fixtures/fizz" schedule: @@ -60,11 +55,6 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/flight-browser" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - package-ecosystem: "npm" directory: "/fixtures/flight-esm" schedule: From b90e440231d3c18a3d9ebbd6a74555e82a16f666 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Thu, 26 Sep 2024 10:22:38 -0400 Subject: [PATCH 206/426] [dependabot] Ignore all fixture directories Seems like we can specify a wildcard dependency name to ignore all dependencies from being updated. As I understand it dependabot will still run monthly but no PRs will be generated. ghstack-source-id: 64b76bd532663cdc4db10ba6299e791b5908d5b1 Pull Request resolved: https://github.com/facebook/react/pull/31074 --- .github/dependabot.yml | 97 +++--------------------------------------- 1 file changed, 5 insertions(+), 92 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4c591dbca1520..11800ad757595 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,97 +1,10 @@ version: 2 updates: - package-ecosystem: "npm" - directory: "/fixtures/art" + directories: + - "/fixtures/*" schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/attribute-behavior" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/concurrent" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/devtools" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/dom" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/eslint" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/expiration" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/fiber-debugger" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/fizz" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/fizz-ssr-browser" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/flight" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/flight-esm" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/legacy-jsx-runtimes" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/nesting" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/packaging" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/scheduler" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/ssr" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/ssr-2" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - - package-ecosystem: "npm" - directory: "/fixtures/stacks" - schedule: - interval: "weekly" + interval: "monthly" open-pull-requests-limit: 0 + ignore: + - dependency-name: "*" From b091ef7e0be078de64721e72b8dc8d7bc33dad29 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Thu, 26 Sep 2024 15:42:59 +0100 Subject: [PATCH 207/426] fix: update release scripts for react devtools (#31069) This has been broken since the migration to GitHub actions. Previously, we've been using `buildId` as an identifier from CircleCI. I've decided to use a commit hash as an identifier, because I don't know if there is a better option, and `scripts/release/download_build_artifacts.js` allows us to download them for a specific commit. --- scripts/devtools/build-and-test.js | 32 +++++++++++------------------ scripts/devtools/publish-release.js | 8 ++++---- scripts/devtools/utils.js | 8 ++++---- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/scripts/devtools/build-and-test.js b/scripts/devtools/build-and-test.js index 3c2f493ddd907..78275691aca9a 100755 --- a/scripts/devtools/build-and-test.js +++ b/scripts/devtools/build-and-test.js @@ -50,13 +50,13 @@ async function main() { }); const archivePath = await archiveGitRevision(); - const buildID = await downloadLatestReactBuild(); + const currentCommitHash = await downloadLatestReactBuild(); await buildAndTestInlinePackage(); await buildAndTestStandalonePackage(); await buildAndTestExtensions(); - saveBuildMetadata({archivePath, buildID}); + saveBuildMetadata({archivePath, currentCommitHash}); printFinalInstructions(); } @@ -197,12 +197,17 @@ async function downloadLatestReactBuild() { console.log(''); + const currentCommitHash = (await exec('git rev-parse HEAD')).stdout.trim(); + if (!currentCommitHash) { + throw new Error('Failed to get current commit hash'); + } + const {commit} = await inquirer.prompt([ { type: 'input', name: 'commit', message: 'Which React version (commit) should be used?', - default: 'main', + default: currentCommitHash, }, ]); console.log(''); @@ -215,24 +220,11 @@ async function downloadLatestReactBuild() { `"${downloadScriptPath}" --commit=${commit}` ); - const output = await logger( - downloadPromise, - 'Downloading React artifacts from CI.', - {estimate: 15000} - ); - - const match = output.match('--build=([0-9]+)'); - if (match.length === 0) { - console.error(chalk.red(`No build ID found in "${output}"`)); - process.exit(1); - } - - const buildID = match[1]; - - console.log(''); - console.log(`Downloaded artifacts for CI build ${chalk.bold(buildID)}.`); + await logger(downloadPromise, 'Downloading React artifacts from CI.', { + estimate: 15000, + }); - return buildID; + return currentCommitHash; } function printFinalInstructions() { diff --git a/scripts/devtools/publish-release.js b/scripts/devtools/publish-release.js index 01ace5fc1bcc8..495fddefc2cd6 100755 --- a/scripts/devtools/publish-release.js +++ b/scripts/devtools/publish-release.js @@ -29,16 +29,16 @@ async function main() { console.log(chalk.bold.green(' ' + pathToPrint)); }); - const {archivePath, buildID} = readSavedBuildMetadata(); + const {archivePath, currentCommitHash} = readSavedBuildMetadata(); await checkNPMPermissions(); await publishToNPM(); - await printFinalInstructions(buildID, archivePath); + await printFinalInstructions(currentCommitHash, archivePath); } -async function printFinalInstructions(buildID, archivePath) { +async function printFinalInstructions(currentCommitHash, archivePath) { console.log(''); console.log( 'You are now ready to publish the extension to Chrome, Edge, and Firefox:' @@ -50,7 +50,7 @@ async function printFinalInstructions(buildID, archivePath) { ); console.log(''); console.log('When publishing to Firefox, remember the following:'); - console.log(` Build id: ${chalk.bold(buildID)}`); + console.log(` Commit Hash: ${chalk.bold(currentCommitHash)}`); console.log(` Git archive: ${chalk.bold(archivePath)}`); console.log(''); console.log('Also consider syncing this release to Facebook:'); diff --git a/scripts/devtools/utils.js b/scripts/devtools/utils.js index 17d0c1f40eb39..06006500627eb 100644 --- a/scripts/devtools/utils.js +++ b/scripts/devtools/utils.js @@ -101,19 +101,19 @@ function readSavedBuildMetadata() { process.exit(1); } - const {archivePath, buildID} = readJsonSync(path); + const {archivePath, currentCommitHash} = readJsonSync(path); - return {archivePath, buildID}; + return {archivePath, currentCommitHash}; } -function saveBuildMetadata({archivePath, buildID}) { +function saveBuildMetadata({archivePath, currentCommitHash}) { const path = join(BUILD_METADATA_TEMP_DIRECTORY, 'metadata'); if (!existsSync(BUILD_METADATA_TEMP_DIRECTORY)) { mkdirSync(BUILD_METADATA_TEMP_DIRECTORY); } - writeJsonSync(path, {archivePath, buildID}, {spaces: 2}); + writeJsonSync(path, {archivePath, currentCommitHash}, {spaces: 2}); } module.exports = { From 204a551eae466ab74ba23870f61dc2b5c71d5ab2 Mon Sep 17 00:00:00 2001 From: Edmond Chui <1967998+EdmondChuiHW@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:39:51 +0100 Subject: [PATCH 208/426] Add: reload to profile for Fusebox (#31021) ## Summary Add reload to profile for Fusebox Stacked on #31048. See https://github.com/facebook/react/pull/31021/commits/6be1977112596581f7ce4cfade572f43320ab06f ## How did you test this change? Test E2E in [D63233256](https://www.internalfb.com/diff/D63233256) --- packages/react-devtools-core/src/backend.js | 13 +++-- .../react-devtools-fusebox/src/frontend.d.ts | 5 +- .../src/attachRenderer.js | 10 +++- .../src/backend/agent.js | 52 ++++++++++--------- .../src/backend/fiber/renderer.js | 16 +++--- .../src/backend/types.js | 14 +++++ packages/react-devtools-shared/src/hook.js | 11 +++- packages/react-devtools-shared/src/utils.js | 45 +++++++++++++++- 8 files changed, 124 insertions(+), 42 deletions(-) diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js index dfc3db15138c6..54a6b9b48a99d 100644 --- a/packages/react-devtools-core/src/backend.js +++ b/packages/react-devtools-core/src/backend.js @@ -26,6 +26,8 @@ import type { import type { DevToolsHook, DevToolsHookSettings, + ReloadAndProfileConfig, + ReloadAndProfileConfigPersistence, } from 'react-devtools-shared/src/backend/types'; import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor'; @@ -40,6 +42,7 @@ type ConnectOptions = { websocket?: ?WebSocket, onSettingsUpdated?: (settings: $ReadOnly) => void, isReloadAndProfileSupported?: boolean, + reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence, }; let savedComponentFilters: Array = @@ -60,8 +63,9 @@ export function initialize( maybeSettingsOrSettingsPromise?: | DevToolsHookSettings | Promise, + reloadAndProfileConfig?: ReloadAndProfileConfig, ) { - installHook(window, maybeSettingsOrSettingsPromise); + installHook(window, maybeSettingsOrSettingsPromise, reloadAndProfileConfig); } export function connectToDevTools(options: ?ConnectOptions) { @@ -82,6 +86,7 @@ export function connectToDevTools(options: ?ConnectOptions) { isAppActive = () => true, onSettingsUpdated, isReloadAndProfileSupported = getIsReloadAndProfileSupported(), + reloadAndProfileConfigPersistence, } = options || {}; const protocol = useHttps ? 'wss' : 'ws'; @@ -175,7 +180,7 @@ export function connectToDevTools(options: ?ConnectOptions) { // TODO (npm-packages) Warn if "isBackendStorageAPISupported" // $FlowFixMe[incompatible-call] found when upgrading Flow - const agent = new Agent(bridge); + const agent = new Agent(bridge, reloadAndProfileConfigPersistence); if (onSettingsUpdated != null) { agent.addListener('updateHookSettings', onSettingsUpdated); } @@ -315,6 +320,7 @@ type ConnectWithCustomMessagingOptions = { resolveRNStyle?: ResolveNativeStyle, onSettingsUpdated?: (settings: $ReadOnly) => void, isReloadAndProfileSupported?: boolean, + reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence, }; export function connectWithCustomMessagingProtocol({ @@ -325,6 +331,7 @@ export function connectWithCustomMessagingProtocol({ resolveRNStyle, onSettingsUpdated, isReloadAndProfileSupported = getIsReloadAndProfileSupported(), + reloadAndProfileConfigPersistence, }: ConnectWithCustomMessagingOptions): Function { const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; if (hook == null) { @@ -361,7 +368,7 @@ export function connectWithCustomMessagingProtocol({ bridge.send('overrideComponentFilters', savedComponentFilters); } - const agent = new Agent(bridge); + const agent = new Agent(bridge, reloadAndProfileConfigPersistence); if (onSettingsUpdated != null) { agent.addListener('updateHookSettings', onSettingsUpdated); } diff --git a/packages/react-devtools-fusebox/src/frontend.d.ts b/packages/react-devtools-fusebox/src/frontend.d.ts index 8a62ad54e504c..74a88c36a85f8 100644 --- a/packages/react-devtools-fusebox/src/frontend.d.ts +++ b/packages/react-devtools-fusebox/src/frontend.d.ts @@ -19,9 +19,12 @@ export type Bridge = { }; export type Store = Object; export type BrowserTheme = 'dark' | 'light'; +export type Config = { + supportsReloadAndProfile?: boolean, +}; export function createBridge(wall: Wall): Bridge; -export function createStore(bridge: Bridge): Store; +export function createStore(bridge: Bridge, config?: Config): Store; export type Source = { sourceURL: string, diff --git a/packages/react-devtools-shared/src/attachRenderer.js b/packages/react-devtools-shared/src/attachRenderer.js index 3138f00cad615..cd7a348b65d71 100644 --- a/packages/react-devtools-shared/src/attachRenderer.js +++ b/packages/react-devtools-shared/src/attachRenderer.js @@ -13,6 +13,7 @@ import type { DevToolsHook, RendererID, } from 'react-devtools-shared/src/backend/types'; +import type {ReloadAndProfileConfig} from './backend/types'; import {attach as attachFlight} from 'react-devtools-shared/src/backend/flight/renderer'; import {attach as attachFiber} from 'react-devtools-shared/src/backend/fiber/renderer'; @@ -29,6 +30,7 @@ export default function attachRenderer( id: RendererID, renderer: ReactRenderer, global: Object, + reloadAndProfileConfig: ReloadAndProfileConfig, ): RendererInterface | void { // only attach if the renderer is compatible with the current version of the backend if (!isMatchingRender(renderer.reconcilerVersion || renderer.version)) { @@ -48,7 +50,13 @@ export default function attachRenderer( renderer.currentDispatcherRef != null ) { // react-reconciler v16+ - rendererInterface = attachFiber(hook, id, renderer, global); + rendererInterface = attachFiber( + hook, + id, + renderer, + global, + reloadAndProfileConfig, + ); } else if (renderer.ComponentTree) { // react-dom v15 rendererInterface = attachLegacy(hook, id, renderer, global); diff --git a/packages/react-devtools-shared/src/backend/agent.js b/packages/react-devtools-shared/src/backend/agent.js index a1e96bfcdeb39..88450fe29ebc9 100644 --- a/packages/react-devtools-shared/src/backend/agent.js +++ b/packages/react-devtools-shared/src/backend/agent.js @@ -8,17 +8,7 @@ */ import EventEmitter from '../events'; -import { - SESSION_STORAGE_LAST_SELECTION_KEY, - SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, - SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, - __DEBUG__, -} from '../constants'; -import { - sessionStorageGetItem, - sessionStorageRemoveItem, - sessionStorageSetItem, -} from 'react-devtools-shared/src/storage'; +import {SESSION_STORAGE_LAST_SELECTION_KEY, __DEBUG__} from '../constants'; import setupHighlighter from './views/Highlighter'; import { initialize as setupTraceUpdates, @@ -36,9 +26,16 @@ import type { RendererID, RendererInterface, DevToolsHookSettings, + ReloadAndProfileConfigPersistence, } from './types'; import type {ComponentFilter} from 'react-devtools-shared/src/frontend/types'; import {isReactNativeEnvironment} from './utils'; +import {defaultReloadAndProfileConfigPersistence} from '../utils'; +import { + sessionStorageGetItem, + sessionStorageRemoveItem, + sessionStorageSetItem, +} from '../storage'; const debug = (methodName: string, ...args: Array) => { if (__DEBUG__) { @@ -159,21 +156,27 @@ export default class Agent extends EventEmitter<{ _persistedSelection: PersistedSelection | null = null; _persistedSelectionMatch: PathMatch | null = null; _traceUpdatesEnabled: boolean = false; + _reloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence; - constructor(bridge: BackendBridge) { + constructor( + bridge: BackendBridge, + reloadAndProfileConfigPersistence?: ReloadAndProfileConfigPersistence = defaultReloadAndProfileConfigPersistence, + ) { super(); - if ( - sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true' - ) { + this._reloadAndProfileConfigPersistence = reloadAndProfileConfigPersistence; + const {getReloadAndProfileConfig, setReloadAndProfileConfig} = + reloadAndProfileConfigPersistence; + const reloadAndProfileConfig = getReloadAndProfileConfig(); + if (reloadAndProfileConfig.shouldReloadAndProfile) { this._recordChangeDescriptions = - sessionStorageGetItem( - SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, - ) === 'true'; + reloadAndProfileConfig.recordChangeDescriptions; this._isProfiling = true; - sessionStorageRemoveItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY); - sessionStorageRemoveItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY); + setReloadAndProfileConfig({ + shouldReloadAndProfile: false, + recordChangeDescriptions: false, + }); } const persistedSelectionString = sessionStorageGetItem( @@ -671,11 +674,10 @@ export default class Agent extends EventEmitter<{ reloadAndProfile: (recordChangeDescriptions: boolean) => void = recordChangeDescriptions => { - sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true'); - sessionStorageSetItem( - SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, - recordChangeDescriptions ? 'true' : 'false', - ); + this._reloadAndProfileConfigPersistence.setReloadAndProfileConfig({ + shouldReloadAndProfile: true, + recordChangeDescriptions, + }); // This code path should only be hit if the shell has explicitly told the Store that it supports profiling. // In that case, the shell must also listen for this specific message to know when it needs to reload the app. diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 22a7afcc4c632..4fac8839ae799 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -42,7 +42,6 @@ import { utfEncodeString, filterOutLocationComponentFilters, } from 'react-devtools-shared/src/utils'; -import {sessionStorageGetItem} from 'react-devtools-shared/src/storage'; import { formatConsoleArgumentsToSingleString, gt, @@ -61,8 +60,6 @@ import { __DEBUG__, PROFILING_FLAG_BASIC_SUPPORT, PROFILING_FLAG_TIMELINE_SUPPORT, - SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, - SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, TREE_OPERATION_ADD, TREE_OPERATION_REMOVE, TREE_OPERATION_REORDER_CHILDREN, @@ -106,6 +103,7 @@ import { supportsOwnerStacks, supportsConsoleTasks, } from './DevToolsFiberComponentStack'; +import type {ReloadAndProfileConfig} from '../types'; // $FlowFixMe[method-unbinding] const toString = Object.prototype.toString; @@ -865,6 +863,7 @@ export function attach( rendererID: number, renderer: ReactRenderer, global: Object, + reloadAndProfileConfig: ReloadAndProfileConfig, ): RendererInterface { // Newer versions of the reconciler package also specific reconciler version. // If that version number is present, use it. @@ -5213,13 +5212,10 @@ export function attach( } // Automatically start profiling so that we don't miss timing info from initial "mount". - if ( - sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true' - ) { - startProfiling( - sessionStorageGetItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY) === - 'true', - ); + if (reloadAndProfileConfig.shouldReloadAndProfile) { + const shouldRecordChangeDescriptions = + reloadAndProfileConfig.recordChangeDescriptions; + startProfiling(shouldRecordChangeDescriptions); } function getNearestFiber(devtoolsInstance: DevToolsInstance): null | Fiber { diff --git a/packages/react-devtools-shared/src/backend/types.js b/packages/react-devtools-shared/src/backend/types.js index c3110dc517fdc..c6f743546e49e 100644 --- a/packages/react-devtools-shared/src/backend/types.js +++ b/packages/react-devtools-shared/src/backend/types.js @@ -485,6 +485,20 @@ export type DevToolsBackend = { setupNativeStyleEditor?: SetupNativeStyleEditor, }; +export type ReloadAndProfileConfig = { + shouldReloadAndProfile: boolean, + recordChangeDescriptions: boolean, +}; + +// Linter doesn't speak Flow's `Partial` type +// eslint-disable-next-line no-undef +type PartialReloadAndProfileConfig = Partial; + +export type ReloadAndProfileConfigPersistence = { + setReloadAndProfileConfig: (config: PartialReloadAndProfileConfig) => void, + getReloadAndProfileConfig: () => ReloadAndProfileConfig, +}; + export type DevToolsHook = { listeners: {[key: string]: Array, ...}, rendererInterfaces: Map, diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index 1916a8c93822c..3b45c7417d4e0 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -16,6 +16,7 @@ import type { RendererInterface, DevToolsBackend, DevToolsHookSettings, + ReloadAndProfileConfig, } from './backend/types'; import { @@ -26,6 +27,7 @@ import { import attachRenderer from './attachRenderer'; import formatConsoleArguments from 'react-devtools-shared/src/backend/utils/formatConsoleArguments'; import formatWithStyles from 'react-devtools-shared/src/backend/utils/formatWithStyles'; +import {defaultReloadAndProfileConfigPersistence} from './utils'; // React's custom built component stack strings match "\s{4}in" // Chrome's prefix matches "\s{4}at" @@ -54,6 +56,7 @@ export function installHook( maybeSettingsOrSettingsPromise?: | DevToolsHookSettings | Promise, + reloadAndProfileConfig?: ReloadAndProfileConfig = defaultReloadAndProfileConfigPersistence.getReloadAndProfileConfig(), ): DevToolsHook | null { if (target.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) { return null; @@ -207,7 +210,13 @@ export function installHook( reactBuildType, }); - const rendererInterface = attachRenderer(hook, id, renderer, target); + const rendererInterface = attachRenderer( + hook, + id, + renderer, + target, + reloadAndProfileConfig, + ); if (rendererInterface != null) { hook.rendererInterfaces.set(id, rendererInterface); hook.emit('renderer-attached', {id, rendererInterface}); diff --git a/packages/react-devtools-shared/src/utils.js b/packages/react-devtools-shared/src/utils.js index a9ebeaaa129da..715834334f360 100644 --- a/packages/react-devtools-shared/src/utils.js +++ b/packages/react-devtools-shared/src/utils.js @@ -36,6 +36,8 @@ import { TREE_OPERATION_UPDATE_TREE_BASE_DURATION, LOCAL_STORAGE_COMPONENT_FILTER_PREFERENCES_KEY, LOCAL_STORAGE_OPEN_IN_EDITOR_URL, + SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, + SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, } from './constants'; import { ComponentFilterElementType, @@ -50,7 +52,12 @@ import { ElementTypeMemo, ElementTypeVirtual, } from 'react-devtools-shared/src/frontend/types'; -import {localStorageGetItem, localStorageSetItem} from './storage'; +import { + localStorageGetItem, + localStorageSetItem, + sessionStorageGetItem, + sessionStorageSetItem, +} from './storage'; import {meta} from './hydration'; import isArray from './isArray'; @@ -62,6 +69,10 @@ import type { } from 'react-devtools-shared/src/frontend/types'; import type {SerializedElement as SerializedElementBackend} from 'react-devtools-shared/src/backend/types'; import {isSynchronousXHRSupported} from './backend/utils'; +import type { + ReloadAndProfileConfig, + ReloadAndProfileConfigPersistence, +} from './backend/types'; // $FlowFixMe[method-unbinding] const hasOwnProperty = Object.prototype.hasOwnProperty; @@ -978,3 +989,35 @@ export function getIsReloadAndProfileSupported(): boolean { return isBackendStorageAPISupported && isSynchronousXHRSupported(); } + +export const defaultReloadAndProfileConfigPersistence: ReloadAndProfileConfigPersistence = + { + setReloadAndProfileConfig({ + shouldReloadAndProfile, + recordChangeDescriptions, + }): void { + if (shouldReloadAndProfile != null) { + sessionStorageSetItem( + SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, + shouldReloadAndProfile ? 'true' : 'false', + ); + } + if (recordChangeDescriptions != null) { + sessionStorageSetItem( + SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, + recordChangeDescriptions ? 'true' : 'false', + ); + } + }, + getReloadAndProfileConfig(): ReloadAndProfileConfig { + return { + shouldReloadAndProfile: + sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === + 'true', + recordChangeDescriptions: + sessionStorageGetItem( + SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY, + ) === 'true', + }; + }, + }; From 60b1420f18e9473230f23f88fdc7b89fea3dbbfd Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 26 Sep 2024 12:55:46 -0400 Subject: [PATCH 209/426] Turn on lazy context propagation for RN and RTR (#31076) Following https://github.com/facebook/react/pull/30935 let's turn this on across the board so we can clean up experiments in RN. --- packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js | 1 - packages/shared/forks/ReactFeatureFlags.native-fb.js | 2 +- packages/shared/forks/ReactFeatureFlags.native-oss.js | 2 +- packages/shared/forks/ReactFeatureFlags.test-renderer.js | 2 +- .../shared/forks/ReactFeatureFlags.test-renderer.native-fb.js | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index 2cae164dfdea5..a7643f6f90151 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -25,5 +25,4 @@ export const enablePersistedModeClonedFlag = __VARIANT__; export const enableShallowPropDiffing = __VARIANT__; export const passChildrenWhenCloningPersistedNodes = __VARIANT__; export const enableFabricCompleteRootInCommitPhase = __VARIANT__; -export const enableLazyContextPropagation = __VARIANT__; export const enableSiblingPrerendering = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 83df5ed548da8..6997bf5f6805e 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -27,7 +27,6 @@ export const { enablePersistedModeClonedFlag, enableShallowPropDiffing, passChildrenWhenCloningPersistedNodes, - enableLazyContextPropagation, enableSiblingPrerendering, } = dynamicFlags; @@ -63,6 +62,7 @@ export const enableGetInspectorDataForInstanceInProduction = true; export const enableHalt = false; export const enableInfiniteRenderLoopDetection = true; export const enableContextProfiling = false; +export const enableLazyContextPropagation = true; export const enableLegacyCache = false; export const enableLegacyFBSupport = false; export const enableLegacyHidden = false; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 55ab25639fea0..729cdef96d2dd 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -52,7 +52,7 @@ export const enableGetInspectorDataForInstanceInProduction = false; export const enableHalt = false; export const enableHiddenSubtreeInsertionEffectCleanup = false; export const enableInfiniteRenderLoopDetection = true; -export const enableLazyContextPropagation = false; +export const enableLazyContextPropagation = true; export const enableContextProfiling = false; export const enableLegacyCache = false; export const enableLegacyFBSupport = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index d12029a672f7c..5e7d56a2a6f3e 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -55,7 +55,7 @@ export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; export const disableSchedulerTimeoutInWorkLoop = false; -export const enableLazyContextPropagation = __EXPERIMENTAL__; +export const enableLazyContextPropagation = true; export const enableContextProfiling = false; export const enableLegacyHidden = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 31b3a118eae5a..e0d946e54ec00 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -42,7 +42,7 @@ export const enableFlightReadableStream = true; export const enableGetInspectorDataForInstanceInProduction = false; export const enableHalt = false; export const enableInfiniteRenderLoopDetection = true; -export const enableLazyContextPropagation = false; +export const enableLazyContextPropagation = true; export const enableContextProfiling = false; export const enableHiddenSubtreeInsertionEffectCleanup = true; export const enableLegacyCache = false; From 76aee6f39d94caa04c11be92d75d12cb9ee56494 Mon Sep 17 00:00:00 2001 From: Ricky Date: Thu, 26 Sep 2024 16:48:57 -0400 Subject: [PATCH 210/426] Revert "Make prerendering always non-blocking" (#31080) Reverts facebook/react#31056 --- .../src/__tests__/ReactDOMFiberAsync-test.js | 2 +- .../src/ReactFiberCompleteWork.js | 5 +- .../react-reconciler/src/ReactFiberLane.js | 32 +- .../src/ReactFiberRootScheduler.js | 20 +- .../src/ReactFiberWorkLoop.js | 293 +++++++----------- .../src/__tests__/ReactDeferredValue-test.js | 12 - .../ReactSiblingPrerendering-test.js | 71 ----- 7 files changed, 137 insertions(+), 298 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index 027099d54707c..ee843996bef1c 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -744,7 +744,7 @@ describe('ReactDOMFiberAsync', () => { // Because it suspended, it remains on the current path expect(div.textContent).toBe('/path/a'); }); - assertLog(gate('enableSiblingPrerendering') ? ['Suspend! [/path/b]'] : []); + assertLog([]); await act(async () => { resolvePromise(); diff --git a/packages/react-reconciler/src/ReactFiberCompleteWork.js b/packages/react-reconciler/src/ReactFiberCompleteWork.js index b24351ac383b9..e3fba900dd116 100644 --- a/packages/react-reconciler/src/ReactFiberCompleteWork.js +++ b/packages/react-reconciler/src/ReactFiberCompleteWork.js @@ -42,7 +42,6 @@ import { enableRenderableContext, passChildrenWhenCloningPersistedNodes, disableLegacyMode, - enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import {now} from './Scheduler'; @@ -623,9 +622,7 @@ function scheduleRetryEffect( // Track the lanes that have been scheduled for an immediate retry so that // we can mark them as suspended upon committing the root. - if (enableSiblingPrerendering) { - markSpawnedRetryLane(retryLane); - } + markSpawnedRetryLane(retryLane); } } diff --git a/packages/react-reconciler/src/ReactFiberLane.js b/packages/react-reconciler/src/ReactFiberLane.js index b98019046e3c2..b8c051def4eef 100644 --- a/packages/react-reconciler/src/ReactFiberLane.js +++ b/packages/react-reconciler/src/ReactFiberLane.js @@ -27,7 +27,6 @@ import { transitionLaneExpirationMs, retryLaneExpirationMs, disableLegacyMode, - enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import {isDevToolsPresent} from './ReactFiberDevToolsHook'; import {clz32} from './clz32'; @@ -271,13 +270,11 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (nonIdlePingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); } else { - if (enableSiblingPrerendering) { - // Nothing has been pinged. Check for lanes that need to be prewarmed. - if (!rootHasPendingCommit) { - const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes; - if (lanesToPrewarm !== NoLanes) { - nextLanes = getHighestPriorityLanes(lanesToPrewarm); - } + // Nothing has been pinged. Check for lanes that need to be prewarmed. + if (!rootHasPendingCommit) { + const lanesToPrewarm = nonIdlePendingLanes & ~warmLanes; + if (lanesToPrewarm !== NoLanes) { + nextLanes = getHighestPriorityLanes(lanesToPrewarm); } } } @@ -297,13 +294,11 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (pingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(pingedLanes); } else { - if (enableSiblingPrerendering) { - // Nothing has been pinged. Check for lanes that need to be prewarmed. - if (!rootHasPendingCommit) { - const lanesToPrewarm = pendingLanes & ~warmLanes; - if (lanesToPrewarm !== NoLanes) { - nextLanes = getHighestPriorityLanes(lanesToPrewarm); - } + // Nothing has been pinged. Check for lanes that need to be prewarmed. + if (!rootHasPendingCommit) { + const lanesToPrewarm = pendingLanes & ~warmLanes; + if (lanesToPrewarm !== NoLanes) { + nextLanes = getHighestPriorityLanes(lanesToPrewarm); } } } @@ -765,14 +760,12 @@ export function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didAttemptEntireTree: boolean, + didSkipSuspendedSiblings: boolean, ) { - // TODO: Split this into separate functions for marking the root at the end of - // a render attempt versus suspending while the root is still in progress. root.suspendedLanes |= suspendedLanes; root.pingedLanes &= ~suspendedLanes; - if (enableSiblingPrerendering && didAttemptEntireTree) { + if (!didSkipSuspendedSiblings) { // Mark these lanes as warm so we know there's nothing else to work on. root.warmLanes |= suspendedLanes; } else { @@ -883,7 +876,6 @@ export function markRootFinished( // suspended) instead of the regular mode (i.e. unwind and skip the siblings // as soon as something suspends to unblock the rest of the update). if ( - enableSiblingPrerendering && suspendedRetryLanes !== NoLanes && // Note that we only do this if there were no updates since we started // rendering. This mirrors the logic in markRootUpdated — whenever we diff --git a/packages/react-reconciler/src/ReactFiberRootScheduler.js b/packages/react-reconciler/src/ReactFiberRootScheduler.js index 39f6f466ed983..9f267e8345e39 100644 --- a/packages/react-reconciler/src/ReactFiberRootScheduler.js +++ b/packages/react-reconciler/src/ReactFiberRootScheduler.js @@ -18,7 +18,6 @@ import { disableSchedulerTimeoutInWorkLoop, enableProfilerTimer, enableProfilerNestedUpdatePhase, - enableSiblingPrerendering, } from 'shared/ReactFeatureFlags'; import { NoLane, @@ -30,7 +29,6 @@ import { markStarvedLanesAsExpired, claimNextTransitionLane, getNextLanesToFlushSync, - checkIfRootIsPrerendering, } from './ReactFiberLane'; import { CommitContext, @@ -208,10 +206,7 @@ function flushSyncWorkAcrossRoots_impl( ? workInProgressRootRenderLanes : NoLanes, ); - if ( - includesSyncLane(nextLanes) && - !checkIfRootIsPrerendering(root, nextLanes) - ) { + if (includesSyncLane(nextLanes)) { // This root has pending sync work. Flush it now. didPerformSomeWork = true; performSyncWorkOnRoot(root, nextLanes); @@ -346,13 +341,7 @@ function scheduleTaskForRootDuringMicrotask( } // Schedule a new callback in the host environment. - if ( - includesSyncLane(nextLanes) && - // If we're prerendering, then we should use the concurrent work loop - // even if the lanes are synchronous, so that prerendering never blocks - // the main thread. - !(enableSiblingPrerendering && checkIfRootIsPrerendering(root, nextLanes)) - ) { + if (includesSyncLane(nextLanes)) { // Synchronous work is always flushed at the end of the microtask, so we // don't need to schedule an additional task. if (existingCallbackNode !== null) { @@ -386,10 +375,9 @@ function scheduleTaskForRootDuringMicrotask( let schedulerPriorityLevel; switch (lanesToEventPriority(nextLanes)) { - // Scheduler does have an "ImmediatePriority", but now that we use - // microtasks for sync work we no longer use that. Any sync work that - // reaches this path is meant to be time sliced. case DiscreteEventPriority: + schedulerPriorityLevel = ImmediateSchedulerPriority; + break; case ContinuousEventPriority: schedulerPriorityLevel = UserBlockingSchedulerPriority; break; diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index ff50ff6973d1e..ec5484c4b6eca 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -765,12 +765,11 @@ export function scheduleUpdateOnFiber( // The incoming update might unblock the current render. Interrupt the // current attempt and restart from the top. prepareFreshStack(root, NoLanes); - const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); } @@ -833,12 +832,11 @@ export function scheduleUpdateOnFiber( // effect of interrupting the current render and switching to the update. // TODO: Make sure this doesn't override pings that happen while we've // already started rendering. - const didAttemptEntireTree = false; markRootSuspended( root, workInProgressRootRenderLanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); } } @@ -900,120 +898,100 @@ export function performWorkOnRoot( // for too long ("expired" work, to prevent starvation), or we're in // sync-updates-by-default mode. const shouldTimeSlice = - (!forceSync && - !includesBlockingLane(lanes) && - !includesExpiredLane(root, lanes)) || - // If we're prerendering, then we should use the concurrent work loop - // even if the lanes are synchronous, so that prerendering never blocks - // the main thread. - // TODO: We should consider doing this whenever a sync lane is suspended, - // even for regular pings. - (enableSiblingPrerendering && checkIfRootIsPrerendering(root, lanes)); - + !forceSync && + !includesBlockingLane(lanes) && + !includesExpiredLane(root, lanes); let exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes, true); + : renderRootSync(root, lanes); - do { + if (exitStatus !== RootInProgress) { let renderWasConcurrent = shouldTimeSlice; - if (exitStatus === RootInProgress) { - // Render phase is still in progress. - if ( - enableSiblingPrerendering && - workInProgressRootIsPrerendering && - !shouldTimeSlice - ) { - // We're in prerendering mode, but time slicing is not enabled. This - // happens when something suspends during a synchronous update. Exit the - // the work loop. When we resume, we'll use the concurrent work loop so - // that prerendering is non-blocking. - // - // Mark the root as suspended. Usually we do this at the end of the - // render phase, but we do it here so that we resume in - // prerendering mode. - // TODO: Consider always calling markRootSuspended immediately. - // Needs to be *after* we attach a ping listener, though. - const didAttemptEntireTree = false; - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); - } - break; - } else if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - const didAttemptEntireTree = !workInProgressRootDidSkipSuspendedSiblings; - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); - } else { - // The render completed. - - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - const finishedWork: Fiber = (root.current.alternate: any); - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes, false); - // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - renderWasConcurrent = false; - // Need to check the exit status again. - continue; - } - - // Check if something threw - if ( - (disableLegacyMode || root.tag !== LegacyRoot) && - exitStatus === RootErrored - ) { - const lanesThatJustErrored = lanes; - const errorRetryLanes = getLanesToRetrySynchronouslyOnError( + do { + if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + markRootSuspended( root, - lanesThatJustErrored, + lanes, + NoLane, + workInProgressRootDidSkipSuspendedSiblings, ); - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( + } else { + // The render completed. + + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + const finishedWork: Fiber = (root.current.alternate: any); + if ( + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) + ) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); + // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + renderWasConcurrent = false; + // Need to check the exit status again. + continue; + } + + // Check if something threw + if ( + (disableLegacyMode || root.tag !== LegacyRoot) && + exitStatus === RootErrored + ) { + const lanesThatJustErrored = lanes; + const errorRetryLanes = getLanesToRetrySynchronouslyOnError( root, lanesThatJustErrored, - errorRetryLanes, ); - renderWasConcurrent = false; - // Need to check the exit status again. - if (exitStatus !== RootErrored) { - // The root did not error this time. Restart the exit algorithm - // from the beginning. - // TODO: Refactor the exit algorithm to be less confusing. Maybe - // more branches + recursion instead of a loop. I think the only - // thing that causes it to be a loop is the RootDidNotComplete - // check. If that's true, then we don't need a loop/recursion - // at all. - continue; - } else { - // The root errored yet again. Proceed to commit the tree. + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + lanesThatJustErrored, + errorRetryLanes, + ); + renderWasConcurrent = false; + // Need to check the exit status again. + if (exitStatus !== RootErrored) { + // The root did not error this time. Restart the exit algorithm + // from the beginning. + // TODO: Refactor the exit algorithm to be less confusing. Maybe + // more branches + recursion instead of a loop. I think the only + // thing that causes it to be a loop is the RootDidNotComplete + // check. If that's true, then we don't need a loop/recursion + // at all. + continue; + } else { + // The root errored yet again. Proceed to commit the tree. + } } } - } - if (exitStatus === RootFatalErrored) { - prepareFreshStack(root, NoLanes); - // Since this is a fatal error, we're going to pretend we attempted - // the entire tree, to avoid scheduling a prerender. - const didAttemptEntireTree = true; - markRootSuspended(root, lanes, NoLane, didAttemptEntireTree); - break; - } + if (exitStatus === RootFatalErrored) { + prepareFreshStack(root, NoLanes); + markRootSuspended( + root, + lanes, + NoLane, + workInProgressRootDidSkipSuspendedSiblings, + ); + break; + } - // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. - finishConcurrentRender(root, exitStatus, finishedWork, lanes); - } - break; - } while (true); + // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. + finishConcurrentRender(root, exitStatus, finishedWork, lanes); + } + break; + } while (true); + } ensureRootIsScheduled(root); } @@ -1046,7 +1024,7 @@ function recoverFromConcurrentError( rootWorkInProgress.flags |= ForceClientRender; } - const exitStatus = renderRootSync(root, errorRetryLanes, false); + const exitStatus = renderRootSync(root, errorRetryLanes); if (exitStatus !== RootErrored) { // Successfully finished rendering on retry @@ -1130,13 +1108,11 @@ function finishConcurrentRender( // This is a transition, so we should exit without committing a // placeholder and without scheduling a timeout. Delay indefinitely // until we receive more data. - const didAttemptEntireTree = - !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); return; } @@ -1192,13 +1168,11 @@ function finishConcurrentRender( // Don't bother with a very short suspense time. if (msUntilTimeout > 10) { - const didAttemptEntireTree = - !workInProgressRootDidSkipSuspendedSiblings; markRootSuspended( root, lanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); const nextLanes = getNextLanes(root, NoLanes); @@ -1312,8 +1286,7 @@ function commitRootWhenReady( completedRenderEndTime, ), ); - const didAttemptEntireTree = !didSkipSuspendedSiblings; - markRootSuspended(root, lanes, spawnedLane, didAttemptEntireTree); + markRootSuspended(root, lanes, spawnedLane, didSkipSuspendedSiblings); return; } } @@ -1436,7 +1409,7 @@ function markRootSuspended( root: FiberRoot, suspendedLanes: Lanes, spawnedLane: Lane, - didAttemptEntireTree: boolean, + didSkipSuspendedSiblings: boolean, ) { // When suspending, we should always exclude lanes that were pinged or (more // rarely, since we try to avoid it) updated during the render phase. @@ -1445,7 +1418,12 @@ function markRootSuspended( suspendedLanes, workInProgressRootInterleavedUpdatedLanes, ); - _markRootSuspended(root, suspendedLanes, spawnedLane, didAttemptEntireTree); + _markRootSuspended( + root, + suspendedLanes, + spawnedLane, + didSkipSuspendedSiblings, + ); } export function flushRoot(root: FiberRoot, lanes: Lanes) { @@ -1987,12 +1965,7 @@ export function renderDidSuspendDelayIfPossible(): void { if ( !workInProgressRootDidSkipSuspendedSiblings && - // Check if the root will be blocked from committing. - // TODO: Consider aligning this better with the rest of the logic. Maybe - // we should only set the exit status to RootSuspendedWithDelay if this - // condition is true? And remove the equivalent checks elsewhere. - (includesOnlyTransitions(workInProgressRootRenderLanes) || - getSuspenseHandler() === null) + !includesBlockingLane(workInProgressRootRenderLanes) ) { // This render may not have originally been scheduled as a prerender, but // something suspended inside the visible part of the tree, which means we @@ -2018,12 +1991,11 @@ export function renderDidSuspendDelayIfPossible(): void { // pinged or updated while we were rendering. // TODO: Consider unwinding immediately, using the // SuspendedOnHydration mechanism. - const didAttemptEntireTree = false; markRootSuspended( workInProgressRoot, workInProgressRootRenderLanes, workInProgressDeferredLane, - didAttemptEntireTree, + workInProgressRootDidSkipSuspendedSiblings, ); } } @@ -2053,11 +2025,7 @@ export function renderHasNotSuspendedYet(): boolean { // TODO: Over time, this function and renderRootConcurrent have become more // and more similar. Not sure it makes sense to maintain forked paths. Consider // unifying them again. -function renderRootSync( - root: FiberRoot, - lanes: Lanes, - shouldYieldForPrerendering: boolean, -): RootExitStatus { +function renderRootSync(root: FiberRoot, lanes: Lanes) { const prevExecutionContext = executionContext; executionContext |= RenderContext; const prevDispatcher = pushDispatcher(root.containerInfo); @@ -2097,7 +2065,6 @@ function renderRootSync( } let didSuspendInShell = false; - let exitStatus = workInProgressRootExitStatus; outer: do { try { if ( @@ -2119,37 +2086,16 @@ function renderRootSync( // Selective hydration. An update flowed into a dehydrated tree. // Interrupt the current render so the work loop can switch to the // hydration lane. - // TODO: I think we might not need to reset the stack here; we can - // just yield and reset the stack when we re-enter the work loop, - // like normal. resetWorkInProgressStack(); - exitStatus = RootDidNotComplete; + workInProgressRootExitStatus = RootDidNotComplete; break outer; } case SuspendedOnImmediate: - case SuspendedOnData: - case SuspendedOnDeprecatedThrowPromise: { - if (getSuspenseHandler() === null) { + case SuspendedOnData: { + if (!didSuspendInShell && getSuspenseHandler() === null) { didSuspendInShell = true; } - const reason = workInProgressSuspendedReason; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - throwAndUnwindWorkLoop(root, unitOfWork, thrownValue, reason); - if ( - enableSiblingPrerendering && - shouldYieldForPrerendering && - workInProgressRootIsPrerendering - ) { - // We've switched into prerendering mode. This implies that we - // suspended outside of a Suspense boundary, which means this - // render will be blocked from committing. Yield to the main - // thread so we can switch to prerendering using the concurrent - // work loop. - exitStatus = RootInProgress; - break outer; - } - break; + // Intentional fallthrough } default: { // Unwind then continue with the normal work loop. @@ -2162,7 +2108,6 @@ function renderRootSync( } } workLoopSync(); - exitStatus = workInProgressRootExitStatus; break; } catch (thrownValue) { handleThrow(root, thrownValue); @@ -2185,6 +2130,14 @@ function renderRootSync( popDispatcher(prevDispatcher); popAsyncDispatcher(prevAsyncDispatcher); + if (workInProgress !== null) { + // This is a sync render, so we should have finished the whole tree. + throw new Error( + 'Cannot commit an incomplete root. This error is likely caused by a ' + + 'bug in React. Please file an issue.', + ); + } + if (__DEV__) { if (enableDebugTracing) { logRenderStopped(); @@ -2195,21 +2148,14 @@ function renderRootSync( markRenderStopped(); } - if (workInProgress !== null) { - // Did not complete the tree. This can happen if something suspended in - // the shell. - } else { - // Normal case. We completed the whole tree. - - // Set this to null to indicate there's no in-progress render. - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; + // Set this to null to indicate there's no in-progress render. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; - // It's safe to process the queue now that the render phase is complete. - finishQueueingConcurrentUpdates(); - } + // It's safe to process the queue now that the render phase is complete. + finishQueueingConcurrentUpdates(); - return exitStatus; + return workInProgressRootExitStatus; } // The work loop is an extremely hot path. Tell Closure not to inline it. @@ -2255,7 +2201,9 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) { // // If we were previously in prerendering mode, check if we received any new // data during an interleaved event. - workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); + if (workInProgressRootIsPrerendering) { + workInProgressRootIsPrerendering = checkIfRootIsPrerendering(root, lanes); + } } if (__DEV__) { @@ -3805,9 +3753,6 @@ function pingSuspendedRoot( // the logic of whether or not a root suspends once it completes. // TODO: If we're rendering sync either due to Sync, Batched or expired, // we should probably never restart. - // TODO: Attach different listeners depending on whether the listener was - // attached during prerendering. Prerender pings should not interrupt - // normal renders. // If we're suspended with delay, or if it's a retry, we'll always suspend // so we can always restart. diff --git a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js index 8ca142cb50517..fd03ba7310f83 100644 --- a/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js +++ b/packages/react-reconciler/src/__tests__/ReactDeferredValue-test.js @@ -420,10 +420,6 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', - - ...(gate('enableSiblingPrerendering') - ? ['Suspend! [Loading...]', 'Suspend! [Final]'] - : []), ]); expect(root).toMatchRenderedOutput(null); @@ -463,10 +459,6 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', - - ...(gate('enableSiblingPrerendering') - ? ['Suspend! [Loading...]', 'Suspend! [Final]'] - : []), ]); expect(root).toMatchRenderedOutput(null); @@ -541,10 +533,6 @@ describe('ReactDeferredValue', () => { // The initial value suspended, so we attempt the final value, which // also suspends. 'Suspend! [Final]', - - ...(gate('enableSiblingPrerendering') - ? ['Suspend! [Loading...]', 'Suspend! [Final]'] - : []), ]); expect(root).toMatchRenderedOutput(null); diff --git a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js index 235e8df2201de..37d907b0fdc65 100644 --- a/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSiblingPrerendering-test.js @@ -479,75 +479,4 @@ describe('ReactSiblingPrerendering', () => { assertLog([]); }, ); - - it( - 'when a synchronous update suspends outside a boundary, the resulting' + - 'prerender is concurrent', - async () => { - function App() { - return ( - <> - - - - - - - ); - } - - const root = ReactNoop.createRoot(); - // Mount the root synchronously - ReactNoop.flushSync(() => root.render()); - - // Synchronously render everything until we suspend in the shell - assertLog(['A', 'B', 'Suspend! [Async]']); - - if (gate('enableSiblingPrerendering')) { - // The rest of the siblings begin to prerender concurrently. Notice - // that we don't unwind here; we pick up where we left off above. - await waitFor(['C']); - await waitFor(['D']); - } - - assertLog([]); - expect(root).toMatchRenderedOutput(null); - - await resolveText('Async'); - assertLog(['A', 'B', 'Async', 'C', 'D']); - expect(root).toMatchRenderedOutput('ABAsyncCD'); - }, - ); - - it('restart a suspended sync render if something suspends while prerendering the siblings', async () => { - function App() { - return ( - <> - - - - - - - ); - } - - const root = ReactNoop.createRoot(); - // Mount the root synchronously - ReactNoop.flushSync(() => root.render()); - - // Synchronously render everything until we suspend in the shell - assertLog(['A', 'B', 'Suspend! [Async]']); - - if (gate('enableSiblingPrerendering')) { - // The rest of the siblings begin to prerender concurrently - await waitFor(['C']); - } - - // While we're prerendering, Async resolves. We should unwind and - // start over, rather than continue prerendering D. - await resolveText('Async'); - assertLog(['A', 'B', 'Async', 'C', 'D']); - expect(root).toMatchRenderedOutput('ABAsyncCD'); - }); }); From 67fee58b1f72754cc77488c40c44e786572ef954 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Thu, 26 Sep 2024 13:51:45 -0700 Subject: [PATCH 211/426] [Fizz] Start initial work immediately (#31079) In a recent update we make Flight start working immediately rather than waitin for a new task. This commit updates fizz to have similar mechanics. We start the render in the currently running task but we do so in a microtask to avoid reentrancy. This aligns Fizz with Flight. ref: https://github.com/facebook/react/pull/30961 --- .../src/__tests__/ReactDOMFizzServer-test.js | 4 +- .../__tests__/ReactDOMFizzServerNode-test.js | 237 +++++++++--------- packages/react-server/src/ReactFizzServer.js | 72 +++--- 3 files changed, 160 insertions(+), 153 deletions(-) diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index a109011b35e98..a2ca222daf04b 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -8119,7 +8119,7 @@ describe('ReactDOMFizzServer', () => { prerendering = false; - const resumed = await ReactDOMFizzServer.resumeToPipeableStream( + const resumed = ReactDOMFizzServer.resumeToPipeableStream( , JSON.parse(JSON.stringify(prerendered.postponed)), { @@ -8187,7 +8187,7 @@ describe('ReactDOMFizzServer', () => { function onPostpone(reason) { postpones.push(reason); } - const result = await renderToPipeableStream(, { + const result = renderToPipeableStream(, { onError, onShellError, onPostpone, diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js index 1e93c2420b8c8..f890840f32b32 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServerNode-test.js @@ -14,6 +14,7 @@ let Stream; let React; let ReactDOMFizzServer; let Suspense; +let act; describe('ReactDOMFizzServerNode', () => { beforeEach(() => { @@ -22,6 +23,7 @@ describe('ReactDOMFizzServerNode', () => { ReactDOMFizzServer = require('react-dom/server'); Stream = require('stream'); Suspense = React.Suspense; + act = require('internal-test-utils').act; }); function getTestWritable() { @@ -54,54 +56,59 @@ describe('ReactDOMFizzServerNode', () => { throw theInfinitePromise; } - it('should call renderToPipeableStream', () => { + it('should call renderToPipeableStream', async () => { const {writable, output} = getTestWritable(); - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( -
hello world
, - ); - pipe(writable); - jest.runAllTimers(); + await act(() => { + const {pipe} = ReactDOMFizzServer.renderToPipeableStream( +
hello world
, + ); + pipe(writable); + }); expect(output.result).toMatchInlineSnapshot(`"
hello world
"`); }); - it('should emit DOCTYPE at the root of the document', () => { + it('should emit DOCTYPE at the root of the document', async () => { const {writable, output} = getTestWritable(); - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( - - hello world - , - ); - pipe(writable); - jest.runAllTimers(); + await act(() => { + const {pipe} = ReactDOMFizzServer.renderToPipeableStream( + + hello world + , + ); + pipe(writable); + }); // with Float, we emit empty heads if they are elided when rendering expect(output.result).toMatchInlineSnapshot( `"hello world"`, ); }); - it('should emit bootstrap script src at the end', () => { + it('should emit bootstrap script src at the end', async () => { const {writable, output} = getTestWritable(); - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( -
hello world
, - { - bootstrapScriptContent: 'INIT();', - bootstrapScripts: ['init.js'], - bootstrapModules: ['init.mjs'], - }, - ); - pipe(writable); - jest.runAllTimers(); + await act(() => { + const {pipe} = ReactDOMFizzServer.renderToPipeableStream( +
hello world
, + { + bootstrapScriptContent: 'INIT();', + bootstrapScripts: ['init.js'], + bootstrapModules: ['init.mjs'], + }, + ); + pipe(writable); + }); expect(output.result).toMatchInlineSnapshot( `"
hello world
"`, ); }); - it('should start writing after pipe', () => { + it('should start writing after pipe', async () => { const {writable, output} = getTestWritable(); - const {pipe} = ReactDOMFizzServer.renderToPipeableStream( -
hello world
, - ); - jest.runAllTimers(); + let pipe; + await act(() => { + pipe = ReactDOMFizzServer.renderToPipeableStream( +
hello world
, + ).pipe; + }); // First we write our header. output.result += 'test'; @@ -281,24 +288,26 @@ describe('ReactDOMFizzServerNode', () => { let isCompleteCalls = 0; const errors = []; const {writable, output, completed} = getTestWritable(); - const {pipe, abort} = ReactDOMFizzServer.renderToPipeableStream( -
- Loading
}> - - -
, - { - onError(x) { - errors.push(x.message); - }, - onAllReady() { - isCompleteCalls++; + let abort; + await act(() => { + const pipeable = ReactDOMFizzServer.renderToPipeableStream( +
+ Loading
}> + + +