Compare commits

..

39 Commits

Author SHA1 Message Date
Mofei Zhang
c19f052b2d [compiler][ez] Move compiler gating tests
Move all gating tests to `gating/`
2025-03-13 11:52:25 -04:00
Mofei Zhang
d2d5350e65 [compiler][optim] more shapes for mixedreadonly
- Add `at`, `indexOf`, and `includes`
- Optimize MixedReadOnly which is currently only used by hook return values. Hook return values are typed as Frozen, this change propagates that to return values of aliasing function calls (such as `at`). One potential issue is that  developers may pass `enableAssumeHooksFollowRulesOfReact:false` and set `transitiveMixedData`, expecting their transitive mixed data to be mutable. This is a bit of an edge case and already doesn't have clear semantics.
2025-03-13 11:52:25 -04:00
Mofei Zhang
8ba22587b5 [compiler][optim] infer mixedReadOnly for numeric and computed properties
Expand type inference to infer mixedReadOnly types for numeric and computed property accesses.
```js
function Component({idx})
  const data = useFragment(...)
  // we want to type `posts` correctly as Array
  const posts = data.viewers[idx].posts.slice(0, 5);
  // ...
}
```
2025-03-13 11:52:25 -04:00
Mofei Zhang
7606b29048 [compiler][optim] Add shape for Array.from
(see title)
2025-03-13 11:52:25 -04:00
Mofei Zhang
54e602d891 [compiler] Patch array and argument spread mutability
Array and argument spreads may mutate stateful iterables. Spread sites should have `ConditionallyMutate` effects (e.g. mutate if the ValueKind is mutable, otherwise read).

See
- [ecma spec (13.2.4.1 Runtime Semantics: ArrayAccumulation. SpreadElement : ... AssignmentExpression)](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-runtime-semantics-arrayaccumulation).
- [ecma spec 13.3.8.1 Runtime Semantics: ArgumentListEvaluation](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-runtime-semantics-argumentlistevaluation)

Note that
- Object and JSX Attribute spreads do not evaluate iterables (srcs [mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#description), [ecma](https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-runtime-semantics-propertydefinitionevaluation))
- An ideal mutability inference system could model known collections (i.e. Arrays or Sets) as a "mutated collection of non-mutable objects" (see `todo-granular-iterator-semantics`), but this is not what we do today. As such, an array / argument spread will always extend the range of built-in arrays, sets, etc
- Due to HIR limitations, call expressions with argument spreads may cause unnecessary bailouts and/or scope merging when we know the call itself has `freeze`, `capture`, or `read` semantics (e.g. `useHook(...mutableValue)`)
  We can deal with this by rewriting these call instructions to (1) create an intermediate array to consume the iterator and (2) capture and spread the array at the callsite
2025-03-13 11:52:25 -04:00
Tyler Scott Williams
ef06b54f8d fix: clarify which mobx libs are not compatible with compiler (#32570)
## Summary

Right now, `react-compiler-healthcheck` flags `mobx` as a "known
incompatible library". But it's not precisely *MobX* that's
incompatible. It's the observer HOC that comes from `mobx-react` and
`mobx-react-lite`.

I've been working on
[mst-use-observable](https://github.com/coolsoftwaretyler/mst-use-observable),
which makes MobX-State-Tree compatible with the compiler. However,
projects that use `mobx-state-tree` and `mst-use-observable` will still
depend on `mobx` as a dependency.

And there [have been efforts in the past to write a hook for
observability](https://github.com/mobxjs/mobx/discussions/2566). So it's
possible that MobX could become compatible, so long as authors access it
with a hook, rather than the HOC.

I would like to propose updating the health check to be a little more
precise and flag the HOC dependencies, rather than MobX itself.

Thanks in advance for your consideration!

## How did you test this change?

`npx react-compiler-healthcheck` shouldn't flag on `mobx` in
dependencies, but will for `mobx-react-lite` and `mobx-react`.

Test suites, formatting, linting, all passed.

---------

Co-authored-by: lauren <poteto@users.noreply.github.com>
2025-03-13 11:46:26 -04:00
Mohhamad Hussain
1b77c3d7b9 Update DEVELOPMENT_GUIDE.md (#32281)
fix: update CONTRIBUTING.md link path

Updated the relative path to CONTRIBUTING.md from `../CONTRIBUTING.md`
to `./../../CONTRIBUTING.md` to ensure the correct file is referenced.

<!--
  Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.

Before submitting a pull request, please make sure the following is
done:

1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
  2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->

## Summary

<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->

## How did you test this change?

<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
  If you leave this empty, your PR will very likely be closed.
-->
2025-03-13 11:45:26 -04:00
michael faith
5ccfcd17ff feat(eslint-plugin-react-hooks): merge rule from eslint-plugin-react-compiler into react-hooks plugin (#32416)
This change merges the `react-compiler` rule from
`eslint-plugin-react-compiler` into the `eslint-plugin-react-hooks`
plugin. In order to do the move in a way that keeps commit history with
the moved files, but also no remove them from their origin until a
future cleanup change can be done, I did the `git mv` first, and then
recreated the files that were moved in their original places, as a
separate commit. Unfortunately GH shows the moved files as new instead
of the ones that are truly new. But in the IDE and `git blame`, commit
history is intact with the moved files.

Since this change adds new dependencies, and one of those dependencies
has a higher `engines` declaration for `node` than what the plugin
currently has, this is technically a breaking change and will have to go
out as part of a major release.

### Related Changes
- https://github.com/facebook/react/pull/32458

---------

Co-authored-by: Lauren Tan <poteto@users.noreply.github.com>
2025-03-12 21:43:06 -04:00
lauren
a8ab2bcb62 [rollup] Add support for running prebuild commands (#32592)
Extracting portions of #32416 for easier review.

Adds a new `prebuild` option to allow for a prebuild command to be run
prior to building the bundle.

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32592).
* __->__ #32592
* #32591
* #32590
* #32589
* #32588

---------

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
2025-03-12 19:12:45 -04:00
lauren
8646349aeb [rollup] Fix codeFrame is not a function (#32591)
Extracting portions of #32416 for easier review.

Fixes a small issue where `codeFrame` is not a function when a rollup
error was encountered.

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32591).
* #32592
* __->__ #32591
* #32590
* #32589
* #32588

---------

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
2025-03-12 19:12:33 -04:00
lauren
f31779a112 [ez] Run Prettier on eslint-plugin-react-compiler/src/types (#32590)
Extracting portions of #32416 for easier review.

This PR contains small formatting fixes.

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32590).
* #32592
* #32591
* __->__ #32590
* #32589
* #32588

---------

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
2025-03-12 19:12:22 -04:00
lauren
0e2402eb20 Update eslint fixtures (#32589)
Extracting portions of #32416 for easier review.

This PR lightly updates the build scripts for the eslint fixtures.

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32589).
* #32592
* #32591
* #32590
* __->__ #32589
* #32588

---------

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
2025-03-12 19:07:51 -04:00
lauren
f695f95290 Update babel configs used in jest (#32588)
Extracting portions of #32416 for easier review.

This PR updates our babel configs (only used in jest) to support
classes.

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32588).
* #32592
* #32591
* #32590
* #32589
* __->__ #32588

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
2025-03-12 19:07:39 -04:00
lauren
5de83dcc0f [playground] Use onMount to check if the editor is available (#32586)
Playground test flakiness seems to be fixed but adding this as an extra
precaution
2025-03-12 18:27:15 -04:00
Jack Pope
5135f98795 Add DOM fixture page for Fragment Ref (#32527)
This adds a page to the DOM fixture to test Fragment Refs. The first
test case is for `addEventListener`/`removeEventListener`.

Setting `enableFragmentRefs` to `__EXPERIMENTAL__` and building is
required to run the fixture.

<img width="872" alt="Screenshot 2025-03-05 at 12 58 57 PM"
src="https://github.com/user-attachments/assets/fee498b7-fd96-4178-9e82-c46d4cb55c9b"
/>
2025-03-12 17:49:44 -04:00
lauren
26bca0005c [playground] Wait for Monaco to fully load (#32584)
I'm not sure what exactly is causing the flakiness in the playground e2e
tests but I suspect it's some kind of timing issue.

Let's try waiting for Monaco to be fully initialized before running
tests.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32584).
* __->__ #32584
* #32583
2025-03-12 17:47:24 -04:00
lauren
e0e98d9560 [playground] Update various deps (#32583)
Updates various deps to align with the rest of the codebase.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32583).
* #32584
* __->__ #32583
2025-03-12 17:47:12 -04:00
lauren
4ab827b869 [compiler] Dedupe @babel/types (#32581)
Extracting portions of #32416 for easier review. This PR dedupes
@babel/types to resolve to 7.26.3, for compatibility in the root
workspace where eslint-plugin-react-hooks resides.

I also needed to update @babel/preset-typescript in snap.

The compiler changes in HIR and ReactiveScopes were needed due to types
changing. Notably, Babel [added support for optional chaining
assignment](https://github.com/babel/babel/pull/15751) (currently [Stage
1](https://github.com/tc39/proposal-optional-chaining-assignment)), so
in the latest versions of @babel/types, AssignmentExpression.left can
now also be of t.OptionalMemberExpression.

Given that this is in Stage 1, the compiler probably shouldn't support
this syntax, so this PR updates HIR to bailout with a TODO if there is a
non LVal on the lhs of an Assignment Expression.

There was also a small superficial SourceLocation change needed in
`InferReactiveScopeVariables` as Babel 8 changes were [accidentally
released in
7](https://github.com/babel/babel/issues/10746#issuecomment-2699146670).
It doesn't affect our analysis so it seems fine to just update with the
new properties.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32581).
* #32582
* __->__ #32581

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>

Co-authored-by: michael faith <michaelfaith@users.noreply.github.com>
2025-03-12 17:02:10 -04:00
mofeiZ
3456b6634a [compiler] Repro for object spread and Array.from with mutable iterators (#32520)
See newly added test fixtures. Repros fixed in later prs of this stack
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32520).
* #32522
* #32521
* __->__ #32520
2025-03-12 15:08:55 -04:00
Sebastian Markbåge
75c979847f Ignore AbortError for gestures (#32579)
Follow up to #32540.

We do allow gestures to be cancelled early (we call skipTransition) if
the gesture stops before it has even started.

This happens in the fixture when we auto-scroll.
2025-03-12 14:20:35 -04:00
Jack Pope
6aa8254bb7 Add ref to Fragment (#32465)
*This API is experimental and subject to change or removal.*

This PR is an alternative to
https://github.com/facebook/react/pull/32421 based on feedback:
https://github.com/facebook/react/pull/32421#pullrequestreview-2625382015
. The difference here is that we traverse from the Fragment's fiber at
operation time instead of keeping a set of children on the
`FragmentInstance`. We still need to handle newly added or removed child
nodes to apply event listeners and observers, so we treat those updates
as effects.

**Fragment Refs**

This PR extends React's Fragment component to accept a `ref` prop. The
Fragment's ref will attach to a custom host instance, which will provide
an Element-like API for working with the Fragment's host parent and host
children.

Here I've implemented `addEventListener`, `removeEventListener`, and
`focus` to get started but we'll be iterating on this by adding
additional APIs in future PRs. This sets up the mechanism to attach refs
and perform operations on children. The FragmentInstance is implemented
in `react-dom` here but is planned for Fabric as well.

The API works by targeting the first level of host children and proxying
Element-like APIs to allow developers to manage groups of elements or
elements that cannot be easily accessed such as from a third-party
library or deep in a tree of Functional Component wrappers.

```javascript
import {Fragment, useRef} from 'react';

const fragmentRef = useRef(null);

<Fragment ref={fragmentRef}>
  <div id="A" />
  <Wrapper>
    <div id="B">
      <div id="C" />
    </div>
  </Wrapper>
  <div id="D" />
</Fragment>
```

In this case, calling `fragmentRef.current.addEventListener()` would
apply an event listener to `A`, `B`, and `D`. `C` is skipped because it
is nested under the first level of Host Component. If another Host
Component was appended as a sibling to `A`, `B`, or `D`, the event
listener would be applied to that element as well and any other APIs
would also affect the newly added child.

This is an implementation of the basic feature as a starting point for
feedback and further iteration.
2025-03-12 10:32:11 -04:00
Sebastian Markbåge
ca8f91f6f6 Log errors from startViewTransition to onRecoverableError (#32540)
We customize the messages only in DEV to keep it small in prod.

We skip some messages that are not really errors but more like
information.
2025-03-11 23:02:45 -04:00
Hendrik Liebau
2398554c60 [Flight]: Client-side registerServerReference must not break .bind() (#32565) 2025-03-11 22:15:38 +01:00
lauren
0ca3deebcf [rcr] Fix incorrect output platform (#32569)
Accidentally copypasted the wrong esbuild config.
2025-03-11 10:41:48 -04:00
Sebastian Markbåge
99e1024051 Check if a child is a new child before calling moveBefore (#32567)
This fixes a critical issue with moveBefore. I was told that the
disconnected -> connected case was going to be relaxed and not be an
error but apparently that is not the case.

This means that we can't use this for initial insertions. Only moves.

Unfortunately React's internals doesn't distinguish these cases. This
adds a hack that checks each nodes but this is pretty bad for
performance. We should only call this in one or the other case.

Given that we still need feature detection. Both of which means that
these calls are no longer inlined and this extra code. I wonder if it's
even worth it given that you can't even rely on it working anyway since
not all browsers have it. Kind of don't want to ship this until all
browsers have it.

Even then we'd ideally refactor React to use separate code paths for
initial insertion vs moves. Which leads to some unfortunate code
duplication.
2025-03-10 18:12:43 -04:00
Sebastian Markbåge
696950aa69 Enable moveBefore in experimental releases (#32549)
Enabling feature detection of early DOM features in a framework is
reckless. I'm not judging other frameworks (but also a little bit).
Because if you do something like `if (moveBefore) moveBefore(a, b) else
insertBefore(a, b)` like we do and then the implementation has to change
there are still too many websites out there that it becomes impossible
to change it. It would break the web. It would instead have to change to
a different name. That's what happened with `contains` -> `includes`.
Counter to popular belief it didn't have anything to do with patching
prototypes. Therefore, ideally frameworks shouldn't start rely on it
until there's two implementations so that there's time for feedback.

That's why we didn't immediately enable this even in experimental.
However, at this point there's probably enough feature detection and it
has shipped long enough in Chrome that it's unlikely to be able to
change at this point.

We can enable it now. For now just in `@experimental` to see if we can
flush out issues with it before bringing it to stable.
2025-03-10 15:27:46 -04:00
Sebastian Markbåge
a8c2bbdabf Cancel finished view transitions Animations manually in fire-and-forget too (#32545)
Otherwise these can survive into the next View Transition and cause
havoc to that transition.

This was appearing as a flash in Safari in the fixture when going from
A->B. This triggers a View Transition and at the same time the scroll
position updates in an effect. That fires a scroll event which starts a
gesture. This shouldn't really happen and the SwipeRecognizer should
ideally ignore those but it's good to surface edge cases. That gesture
is blocked on the View Transition finishing and then immediately after
it starts a gesture View Transition. That gesture then picked up the
former Animation from the previous transition which caused issues. This
PR fixes that flash.
2025-03-10 15:27:37 -04:00
Jack Pope
50ab2dde94 Make renameElementSymbol dynamic for native fb (#32566)
Use variant to begin rolling this out internally.
2025-03-10 15:24:09 -04:00
lauren
d331ba0411 [ci] Fix incorrect condition (#32551)
Fixes an incorrect condition for running tests in the compiler
workspace.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32551).
* __->__ #32551
* #32550
2025-03-07 16:43:38 -05:00
lauren
00aa0043c7 [compiler] Migrate compiler packages to tsup (#32550)
Currently in the `compiler` workspace, we invoke esbuild directly to
build most packages (with the exception of `snap`). This has been mostly
fine, but does not allow us to do things like generate type declaration
files.

I would like #32416 to be able to consume the merged
eslint-plugin-react-compiler from source rather than via npm, and one of
the things that has come up from my exploration in that stack using the
compiler from source is that babel-plugin-react-compiler is missing type
declarations. This is primarily because React's build process uses
rollup + rollup-plugin-typescript, which runs tsc. So the merged plugin
needs to typecheck properly in order to build. An alternative might be
to migrate to something like babel with rollup instead to simply strip
types rather than typecheck before building. The minor downside of that
approach is that we would need to manually maintain a d.ts file for
eslint-plugin-react-hooks. For now I would like to see if this PR helps
us make progress rather than go for the slightly worse alternative.

[`tsup`](https://github.com/egoist/tsup) is esbuild based so build
performance is comparable. It is slower when generating d.ts files, but
it's still much faster than rollup which we used prior to esbuild. For
now, I have turned off `dts` by default, and it is only passed when
publishing on npm.

If you want to also generate d.ts files you can run `yarn build --dts`.

```
# BEFORE: build all compiler packages (esbuild)
$ time yarn build

  Done in 15.61s.
yarn build  13.82s user 1.54s system 96% cpu 15.842 total

# ---

# AFTER: build all compiler packages (tsup)
$ time yarn build

  Done in 12.39s.
yarn build  12.58s user 1.68s system 106% cpu 13.350 total

# ---

# AFTER: build all compiler packages and type declarations (tsup)
$ time yarn build --dts

  Done in 30.69s.
yarn build  43.57s user 3.20s system 150% cpu 31.061 total
```

I still need to test if this unblocks #32416 but this stack can be
landed independently though as we could probably just release type
declarations on npm. No one should be using the compiler directly, but
if they really wanted to, lack of type declarations would not stop them
(cf React secret internals).

Note that I still kept esbuild as we still use it directly for forgive.
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32550).
* #32551
* __->__ #32550
2025-03-07 16:41:55 -05:00
Nick Lefever
cc680065c3 Fix asserts caused by OffscreenComponent rendering in React Native with passChildrenWhenCloningPersistedNodes (#32528)
<!--
  Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.

Before submitting a pull request, please make sure the following is
done:

1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
  2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->

## Summary

<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->

This PR fixes asserts when `passChildrenWhenCloningPersistedNodes` is
enabled for React Native and OffscreenComponent child rendering unhides
host components.

Discussions around possible fixes for the asserts seen in React Native
suggested changing the way we handle hiding/unhiding host components by
updating the fiber state with the hidden host component instead of
submitting a hidden clone Fabric and keeping the original as the current
fiber.

Implementing this fix would require holding onto the original styling of
the hidden host component. The reconciler updates the styling by adding
`display: none` to hide the contents. If the original host component was
already hidden, the renderer would lose that information and remove the
styling when showing the contents again.

To reduce the changes required to make
`passChildrenWhenCloningPersistedNodes` work, this PR falls back to the
original cloning method when OffscreenComponents are part of the
children needed to be added back. This effectively resolve the asserts
triggered by the feature in RN and improves overall performance.

## How did you test this change?

<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
  If you leave this empty, your PR will very likely be closed.
-->

This fix was tested by enabling `passChildrenWhenCloningPersistedNodes`
in an app built with React Native that had a repro for triggering the
asserts. The asserts do not occur anymore when using the changes in this
PR.

---------

Co-authored-by: Nick <lefever@meta.com>
2025-03-07 17:03:59 +00:00
Ricky
f9d78089c6 [flags] make enableComponentPerformanceTrack dynamic (#32359) 2025-03-06 14:00:12 -05:00
Mathias Stang
562f17efab docs(eslint-plugin-react-hooks): add changelog for 5.1.0 & 5.2.0 (#32536)
<!--
  Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.

Before submitting a pull request, please make sure the following is
done:

1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
  2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
  9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
  10. If you haven't already, complete the CLA.

Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->

## Summary

<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->

Adds changelog entries for the last two minor releases of
`eslint-plugin-react-hooks`. Fixes #31717.

I chose to not include #31208 (8382581446)
and #32115 (fd2d279984) in the changelog
as they only changed internals that do not affect consumers of the
plugin, and it doesn't seem like the changelog previously included such
changes.

Changes are sorted by importance (rather than by commit date), with the
most important changes first.

## How did you test this change?

<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
  If you leave this empty, your PR will very likely be closed.
-->

Docs only, nothing to test.
2025-03-06 13:58:39 -05:00
lauren
9e9b54d7f6 [compiler] Make CompilerError compatible with reflection (#32539) 2025-03-06 13:06:36 -05:00
Sebastian "Sebbie" Silbermann
029e8bd618 Add Owner Stack to attribute hydration mismatches (#32538) 2025-03-06 17:12:50 +01:00
Sebastian Markbåge
e81fcfe3f2 [Flight] Expose registerServerReference from the client builds (#32534)
This is used to register Server References that exist in the current
environment but also exists in the server it might call into. Such as a
remote server.

If the value comes from the remote server in the first place then this
is called automatically to ensure that you can pass a reference back to
where it came from - even if the `serverModuleMap` option is used. This
was already the case when `serverModuleMap` wasn't passed. This is how
you can pass server references back to the server. However, when we
added `serverModuleMap` that pass was skipped because we were getting
real functions instead of proxies.

For functions that wasn't yet passed from the remote server to the
current server, we can register them eagerly just like we do for
`import('/server').registerServerReference()`. You can now also do this
with `import('/client').registerServerReference()`. We could make them
shared so you only have to do this once but it might not be possible to
pass to the remote server and the remote server might not even be the
same RSC renderer. Therefore I split them. It's up to the compiler
whether it should do that or not. It has to know that any function you
might call might be able to receive it. This is currently global to a
specific RSC renderer.
2025-03-05 22:16:56 -05:00
Keith Cirkel
aac177c484 Support beforetoggle/toggle events for dialog (#32479) 2025-03-05 19:45:16 +01:00
lauren
6b1ae49571 [ez] Remove unused netlify.toml (#32530)
I don't think this is in use anymore
2025-03-05 12:24:45 -05:00
Sebastian Markbåge
e03ac20f94 Set direction in animate call directly (#32523)
Setting the animation's currentTime causes a quirk where the transition
can end up off by a bit and the end state can be slightly off the end
time.

However, I realized that we don't have to because if we just set the
direction in the `animate()` call directly the Safari bug goes away.
2025-03-05 09:33:06 -05:00
198 changed files with 8599 additions and 1934 deletions

View File

@@ -96,4 +96,4 @@ jobs:
- run: xvfb-run -a yarn workspace ${{ matrix.workspace_name }} test
if: runner.os == 'Linux' && matrix.workspace_name == 'react-forgive'
- run: yarn workspace ${{ matrix.workspace_name }} test
if: runner.os != 'Linux' && matrix.workspace_name != 'react-forgive'
if: matrix.workspace_name != 'react-forgive'

View File

@@ -0,0 +1,19 @@
'use strict';
/**
* HACK: @poteto React Compiler inlines Zod in its build artifact. Zod spreads values passed to .map
* which causes issues in @babel/plugin-transform-spread in loose mode, as it will result in
* {undefined: undefined} which fails to parse.
*
* [@babel/plugin-transform-block-scoping', {throwIfClosureRequired: true}] also causes issues with
* the built version of the compiler. The minimal set of plugins needed for this file is reexported
* from babel.config-ts.
*
* I will remove this hack later when we move eslint-plugin-react-hooks into the compiler directory.
**/
const baseConfig = require('./babel.config-ts');
module.exports = {
plugins: baseConfig.plugins,
};

View File

@@ -7,6 +7,8 @@ module.exports = {
plugins: [
'@babel/plugin-syntax-jsx',
'@babel/plugin-transform-flow-strip-types',
['@babel/plugin-transform-class-properties', {loose: true}],
'@babel/plugin-transform-classes',
],
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],

View File

@@ -4,7 +4,8 @@ module.exports = {
plugins: [
'@babel/plugin-syntax-jsx',
'@babel/plugin-transform-flow-strip-types',
['@babel/plugin-proposal-class-properties', {loose: true}],
['@babel/plugin-transform-class-properties', {loose: true}],
'@babel/plugin-transform-classes',
'syntax-trailing-function-commas',
[
'@babel/plugin-proposal-object-rest-spread',

View File

@@ -9,6 +9,13 @@ import {expect, test} from '@playwright/test';
import {encodeStore, type Store} from '../../lib/stores';
import {format} from 'prettier';
function isMonacoLoaded(): boolean {
return (
typeof window['MonacoEnvironment'] !== 'undefined' &&
window['__MONACO_LOADED__'] === true
);
}
function formatPrint(data: Array<string>): Promise<string> {
return format(data.join(''), {parser: 'babel'});
}
@@ -105,6 +112,7 @@ function nonReactFn() {
test('editor should open successfully', async ({page}) => {
await page.goto(`/`, {waitUntil: 'networkidle'});
await page.waitForFunction(isMonacoLoaded);
await page.screenshot({
fullPage: true,
path: 'test-results/00-fresh-page.png',
@@ -120,6 +128,7 @@ test('editor should compile from hash successfully', async ({page}) => {
};
const hash = encodeStore(store);
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
await page.waitForFunction(isMonacoLoaded);
// User input from hash compiles
await page.screenshot({
@@ -143,6 +152,7 @@ test('reset button works', async ({page}) => {
};
const hash = encodeStore(store);
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
await page.waitForFunction(isMonacoLoaded);
// Reset button works
page.on('dialog', dialog => dialog.accept());
@@ -166,6 +176,7 @@ TEST_CASE_INPUTS.forEach((t, idx) =>
};
const hash = encodeStore(store);
await page.goto(`/#${hash}`, {waitUntil: 'networkidle'});
await page.waitForFunction(isMonacoLoaded);
await page.screenshot({
fullPage: true,
path: `test-results/03-0${idx}-${t.name}.png`,

View File

@@ -89,6 +89,9 @@ export default function Input({errors, language}: Props): JSX.Element {
_: editor.IStandaloneCodeEditor,
monaco: Monaco,
) => void = (_, monaco) => {
if (typeof window !== 'undefined') {
window['__MONACO_LOADED__'] = true;
}
setMonaco(monaco);
const tscOptions = {

View File

@@ -12,7 +12,7 @@
"vercel-build": "yarn build",
"start": "next start",
"lint": "next lint",
"test": "playwright test"
"test": "playwright test --workers=4"
},
"dependencies": {
"@babel/core": "^7.18.9",
@@ -22,9 +22,9 @@
"@babel/plugin-transform-block-scoping": "^7.18.9",
"@babel/plugin-transform-modules-commonjs": "^7.18.9",
"@babel/preset-react": "^7.18.9",
"@babel/preset-typescript": "^7.18.9",
"@babel/preset-typescript": "^7.26.0",
"@babel/traverse": "^7.18.9",
"@babel/types": "7.18.9",
"@babel/types": "7.26.3",
"@heroicons/react": "^1.0.6",
"@monaco-editor/react": "^4.4.6",
"@playwright/test": "^1.42.1",
@@ -39,13 +39,13 @@
"prettier": "^3.3.3",
"pretty-format": "^29.3.1",
"re-resizable": "^6.9.16",
"react": "19.0.0-rc-77b637d6-20241016",
"react-dom": "19.0.0-rc-77b637d6-20241016"
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/node": "18.11.9",
"@types/react": "npm:types-react@19.0.0-rc.1",
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"autoprefixer": "^10.4.13",
"clsx": "^1.2.1",
"concurrently": "^7.4.0",
@@ -55,9 +55,5 @@
"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"
}
}

View File

@@ -23,7 +23,7 @@ export default defineConfig({
// Test directory
testDir: path.join(__dirname, '__tests__/e2e'),
// If a test fails, retry it additional 2 times
retries: 2,
retries: 3,
// Artifacts folder where screenshots, videos, and traces are stored.
outputDir: 'test-results/',
// Note: we only use text snapshots, so its safe to omit the host environment name

View File

@@ -23,6 +23,15 @@
"@babel/highlight" "^7.24.7"
picocolors "^1.0.0"
"@babel/code-frame@^7.26.2":
version "7.26.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
dependencies:
"@babel/helper-validator-identifier" "^7.25.9"
js-tokens "^4.0.0"
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"
@@ -59,6 +68,17 @@
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^2.5.1"
"@babel/generator@^7.26.10":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.10.tgz#a60d9de49caca16744e6340c3658dfef6138c3f7"
integrity sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==
dependencies:
"@babel/parser" "^7.26.10"
"@babel/types" "^7.26.10"
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^3.0.2"
"@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"
@@ -66,6 +86,13 @@
dependencies:
"@babel/types" "^7.24.7"
"@babel/helper-annotate-as-pure@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4"
integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==
dependencies:
"@babel/types" "^7.25.9"
"@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"
@@ -77,26 +104,26 @@
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==
"@babel/helper-create-class-features-plugin@^7.25.9":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz#d6f83e3039547fbb39967e78043cd3c8b7820c71"
integrity sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==
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"
"@babel/helper-annotate-as-pure" "^7.25.9"
"@babel/helper-member-expression-to-functions" "^7.25.9"
"@babel/helper-optimise-call-expression" "^7.25.9"
"@babel/helper-replace-supers" "^7.26.5"
"@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
"@babel/traverse" "^7.26.9"
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==
"@babel/helper-member-expression-to-functions@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3"
integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==
dependencies:
"@babel/traverse" "^7.24.8"
"@babel/types" "^7.24.8"
"@babel/traverse" "^7.25.9"
"@babel/types" "^7.25.9"
"@babel/helper-module-imports@^7.24.7":
version "7.24.7"
@@ -106,6 +133,14 @@
"@babel/traverse" "^7.24.7"
"@babel/types" "^7.24.7"
"@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.25.9"
"@babel/types" "^7.25.9"
"@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"
@@ -116,26 +151,40 @@
"@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==
"@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/types" "^7.24.7"
"@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.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e"
integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==
dependencies:
"@babel/types" "^7.25.9"
"@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==
"@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5":
version "7.26.5"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35"
integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==
"@babel/helper-replace-supers@^7.26.5":
version "7.26.5"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz#6cb04e82ae291dae8e72335dfe438b0725f14c8d"
integrity sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==
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-member-expression-to-functions" "^7.25.9"
"@babel/helper-optimise-call-expression" "^7.25.9"
"@babel/traverse" "^7.26.5"
"@babel/helper-simple-access@^7.24.7":
version "7.24.7"
@@ -145,29 +194,39 @@
"@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==
"@babel/helper-skip-transparent-expression-wrappers@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9"
integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==
dependencies:
"@babel/traverse" "^7.24.7"
"@babel/types" "^7.24.7"
"@babel/traverse" "^7.25.9"
"@babel/types" "^7.25.9"
"@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-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.24.7":
"@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-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.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/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/helpers@^7.25.0":
version "7.25.6"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.6.tgz#57ee60141829ba2e102f30711ffe3afab357cc60"
@@ -193,6 +252,13 @@
dependencies:
"@babel/types" "^7.25.6"
"@babel/parser@^7.26.10", "@babel/parser@^7.26.9":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.10.tgz#e9bdb82f14b97df6569b0b038edd436839c57749"
integrity sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==
dependencies:
"@babel/types" "^7.26.10"
"@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"
@@ -200,13 +266,27 @@
dependencies:
"@babel/helper-plugin-utils" "^7.24.7"
"@babel/plugin-syntax-typescript@^7.18.9", "@babel/plugin-syntax-typescript@^7.24.7":
"@babel/plugin-syntax-jsx@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290"
integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==
dependencies:
"@babel/helper-plugin-utils" "^7.25.9"
"@babel/plugin-syntax-typescript@^7.18.9":
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-syntax-typescript@^7.25.9":
version "7.25.9"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399"
integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==
dependencies:
"@babel/helper-plugin-utils" "^7.25.9"
"@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"
@@ -214,7 +294,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.24.8"
"@babel/plugin-transform-modules-commonjs@^7.18.9", "@babel/plugin-transform-modules-commonjs@^7.24.7":
"@babel/plugin-transform-modules-commonjs@^7.18.9":
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==
@@ -223,6 +303,14 @@
"@babel/helper-plugin-utils" "^7.24.8"
"@babel/helper-simple-access" "^7.24.7"
"@babel/plugin-transform-modules-commonjs@^7.25.9":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz#8f011d44b20d02c3de44d8850d971d8497f981fb"
integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==
dependencies:
"@babel/helper-module-transforms" "^7.26.0"
"@babel/helper-plugin-utils" "^7.25.9"
"@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"
@@ -256,16 +344,16 @@
"@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==
"@babel/plugin-transform-typescript@^7.25.9":
version "7.26.8"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.8.tgz#2e9caa870aa102f50d7125240d9dbf91334b0950"
integrity sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==
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/helper-annotate-as-pure" "^7.25.9"
"@babel/helper-create-class-features-plugin" "^7.25.9"
"@babel/helper-plugin-utils" "^7.26.5"
"@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
"@babel/plugin-syntax-typescript" "^7.25.9"
"@babel/preset-react@^7.18.9":
version "7.24.7"
@@ -279,16 +367,16 @@
"@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==
"@babel/preset-typescript@^7.26.0":
version "7.26.0"
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz#4a570f1b8d104a242d923957ffa1eaff142a106d"
integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==
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/helper-plugin-utils" "^7.25.9"
"@babel/helper-validator-option" "^7.25.9"
"@babel/plugin-syntax-jsx" "^7.25.9"
"@babel/plugin-transform-modules-commonjs" "^7.25.9"
"@babel/plugin-transform-typescript" "^7.25.9"
"@babel/runtime@^7.21.0":
version "7.25.6"
@@ -306,7 +394,16 @@
"@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":
"@babel/template@^7.26.9":
version "7.26.9"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.26.9.tgz#4577ad3ddf43d194528cff4e1fa6b232fa609bb2"
integrity sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==
dependencies:
"@babel/code-frame" "^7.26.2"
"@babel/parser" "^7.26.9"
"@babel/types" "^7.26.9"
"@babel/traverse@^7.18.9", "@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==
@@ -319,22 +416,34 @@
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==
"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.9":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.10.tgz#43cca33d76005dbaa93024fae536cc1946a4c380"
integrity sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==
dependencies:
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
"@babel/code-frame" "^7.26.2"
"@babel/generator" "^7.26.10"
"@babel/parser" "^7.26.10"
"@babel/template" "^7.26.9"
"@babel/types" "^7.26.10"
debug "^4.3.1"
globals "^11.1.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==
"@babel/types@7.26.3", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.6":
version "7.26.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
dependencies:
"@babel/helper-string-parser" "^7.24.8"
"@babel/helper-validator-identifier" "^7.24.7"
to-fast-properties "^2.0.0"
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.26.9":
version "7.26.10"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259"
integrity sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==
dependencies:
"@babel/helper-string-parser" "^7.25.9"
"@babel/helper-validator-identifier" "^7.25.9"
"@emnapi/runtime@^1.2.0":
version "1.3.1"
@@ -733,17 +842,15 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
"@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-dom@^19.0.0":
version "19.0.4"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.4.tgz#bedba97f9346bd4c0fe5d39e689713804ec9ac89"
integrity sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==
"@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==
"@types/react@^19.0.0":
version "19.0.10"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.10.tgz#d0c66dafd862474190fe95ce11a68de69ed2b0eb"
integrity sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==
dependencies:
csstype "^3.0.2"
@@ -2468,6 +2575,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.1.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
@@ -3025,12 +3137,12 @@ re-resizable@^6.9.16:
resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.10.0.tgz#d684a096ab438f1a93f59ad3a580a206b0ce31ee"
integrity sha512-hysSK0xmA5nz24HBVztlk4yCqCLCvS32E6ZpWxVKop9x3tqCa4yAj1++facrmkOf62JsJHjmjABdKxXofYioCw==
react-dom@19.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==
react-dom@^19.0.0:
version "19.0.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
dependencies:
scheduler "0.25.0-rc-77b637d6-20241016"
scheduler "^0.25.0"
react-is@^16.13.1:
version "16.13.1"
@@ -3042,10 +3154,10 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
react@19.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==
react@^19.0.0:
version "19.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
read-cache@^1.0.0:
version "1.0.0"
@@ -3167,10 +3279,10 @@ safe-regex-test@^1.0.3:
es-errors "^1.3.0"
is-regex "^1.1.4"
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==
scheduler@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
semver@^6.3.1:
version "6.3.1"
@@ -3517,11 +3629,6 @@ thenify-all@^1.0.0:
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"

View File

@@ -1,6 +1,6 @@
# React Compiler Development Guide
Note: for general notes about contributing, see the [CONTRIBUTING.md](../CONTRIBUTING.md).
Note: for general notes about contributing, see the [CONTRIBUTING.md](../../CONTRIBUTING.md).
## Compiler Development

View File

@@ -26,6 +26,7 @@
"react-is": "0.0.0-experimental-4beb1fd8-20241118"
},
"devDependencies": {
"@babel/types": "^7.26.0",
"@tsconfig/strictest": "^2.0.5",
"concurrently": "^7.4.0",
"esbuild": "^0.25.0",
@@ -37,12 +38,15 @@
"prettier-plugin-hermes-parser": "^0.26.0",
"prompt-promise": "^1.0.3",
"rimraf": "^5.0.10",
"to-fast-properties": "^2.0.0",
"tsup": "^8.4.0",
"typescript": "^5.4.3",
"wait-on": "^7.2.0",
"yargs": "^17.7.2"
},
"resolutions": {
"rimraf": "5.0.10"
"rimraf": "5.0.10",
"@babel/types": "7.26.3"
},
"packageManager": "yarn@1.22.22"
}

View File

@@ -9,7 +9,7 @@
"!*.tsbuildinfo"
],
"scripts": {
"build": "rimraf dist && scripts/build.js",
"build": "rimraf dist && tsup",
"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",
@@ -17,10 +17,10 @@
"snap:ci": "yarn snap:build && yarn snap",
"ts:analyze-trace": "scripts/ts-analyze-trace.sh",
"lint": "yarn eslint src",
"watch": "scripts/build.js --watch"
"watch": "yarn build --watch"
},
"dependencies": {
"@babel/types": "^7.19.0"
"@babel/types": "^7.26.0"
},
"devDependencies": {
"@babel/core": "^7.2.0",
@@ -50,7 +50,6 @@
"pretty-format": "^24",
"react": "0.0.0-experimental-4beb1fd8-20241118",
"react-dom": "0.0.0-experimental-4beb1fd8-20241118",
"react-compiler-runtime": "0.0.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"zod": "^3.22.4",

View File

@@ -1,61 +0,0 @@
#!/usr/bin/env node
/**
* 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.
*/
const esbuild = require('esbuild');
const yargs = require('yargs');
const path = require('path');
const argv = yargs(process.argv.slice(2))
.options('w', {
alias: 'watch',
default: false,
type: 'boolean',
})
.parse();
const config = {
entryPoints: [path.join(__dirname, '../src/index.ts')],
outfile: path.join(__dirname, '../dist/index.js'),
bundle: true,
external: ['@babel/types'],
format: 'cjs',
platform: 'node',
banner: {
js: `/**
* 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
*/
"use no memo";`,
},
};
async function main() {
if (argv.w) {
const ctx = await esbuild.context(config);
await ctx.watch();
console.log('watching for changes...');
} else {
await esbuild.build({
sourcemap: true,
minify: false,
...config,
});
}
}
main();

View File

@@ -29,7 +29,6 @@ const e2eTransformerCacheKey = 1;
const forgetOptions: EnvironmentConfig = validateEnvironmentConfig({
enableAssumeHooksFollowRulesOfReact: true,
enableFunctionOutlining: false,
enableEmitHookGuards: null,
});
const debugMode = process.env['DEBUG_FORGET_COMPILER'] != null;

View File

@@ -61,18 +61,6 @@ export default function BabelPluginReactCompiler(
},
};
}
if (opts.environment.enableEmitHookGuards != null) {
const enableEmitHookGuards = opts.environment.enableEmitHookGuards;
if (enableEmitHookGuards.devonly === true && !isDev) {
opts = {
...opts,
environment: {
...opts.environment,
enableEmitHookGuards: null,
},
};
}
}
compileProgram(prog, {
opts,
filename: pass.filename ?? null,

View File

@@ -188,6 +188,7 @@ export class CompilerError extends Error {
constructor(...args: Array<any>) {
super(...args);
this.name = 'ReactCompilerError';
this.details = [];
}
override get message(): string {
@@ -197,7 +198,10 @@ export class CompilerError extends Error {
override set message(_message: string) {}
override toString(): string {
return this.details.map(detail => detail.toString()).join('\n\n');
if (Array.isArray(this.details)) {
return this.details.map(detail => detail.toString()).join('\n\n');
}
return this.name;
}
push(options: CompilerErrorDetailOptions): CompilerErrorDetail {

View File

@@ -3,6 +3,9 @@ import {hasOwnProperty} from '../Utils/utils';
import {PluginOptions} from './Options';
function hasModule(name: string): boolean {
if (typeof require === 'undefined') {
return false;
}
try {
return !!require.resolve(name);
} catch (error: any) {

View File

@@ -1909,16 +1909,31 @@ function lowerExpression(
if (operator === '=') {
const left = expr.get('left');
return lowerAssignment(
builder,
left.node.loc ?? GeneratedSource,
InstructionKind.Reassign,
left,
lowerExpressionToTemporary(builder, expr.get('right')),
left.isArrayPattern() || left.isObjectPattern()
? 'Destructure'
: 'Assignment',
);
if (left.isLVal()) {
return lowerAssignment(
builder,
left.node.loc ?? GeneratedSource,
InstructionKind.Reassign,
left,
lowerExpressionToTemporary(builder, expr.get('right')),
left.isArrayPattern() || left.isObjectPattern()
? 'Destructure'
: 'Assignment',
);
} else {
/**
* OptionalMemberExpressions as the left side of an AssignmentExpression are Stage 1 and
* not supported by React Compiler yet.
*/
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Unsupported syntax on the left side of an AssignmentExpression`,
description: `Expected an LVal, got: ${left.type}`,
severity: ErrorSeverity.Todo,
loc: left.node.loc ?? null,
suggestions: null,
});
return {kind: 'UnsupportedNode', node: exprNode, loc: exprLoc};
}
}
const operators: {
@@ -2091,7 +2106,7 @@ function lowerExpression(
propName = namePath.node.name;
if (propName.indexOf(':') !== -1) {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name \`${name}\``,
reason: `(BuildHIR::lowerExpression) Unexpected colon in attribute name \`${propName}\``,
severity: ErrorSeverity.Todo,
loc: namePath.node.loc ?? null,
suggestions: null,

View File

@@ -396,27 +396,7 @@ const EnvironmentConfigSchema = z.object({
*/
enableEmitFreeze: ExternalFunctionSchema.nullable().default(null),
enableEmitHookGuards: z
.intersection(
ExternalFunctionSchema,
z.object({
devonly: z.union([
z.literal(true),
z.literal(false),
/**
* Backwards compatibility with previous configuration, which did not
* have this field.
*/
z.literal(undefined),
]),
}),
)
.nullable()
.default({
source: 'react-compiler-runtime',
importSpecifierName: '$dispatcherGuard',
devonly: true,
}),
enableEmitHookGuards: ExternalFunctionSchema.nullable().default(null),
/**
* Enable instruction reordering. See InstructionReordering.ts for the details
@@ -683,12 +663,11 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
source: 'react-compiler-runtime',
importSpecifierName: 'shouldInstrument',
},
globalGating: '__DEV__',
globalGating: 'DEV',
},
enableEmitHookGuards: {
source: 'react-compiler-runtime',
importSpecifierName: '$dispatcherGuard',
devonly: false,
},
inlineJsxTransform: {
elementSymbol: 'react.transitional.element',
@@ -732,7 +711,6 @@ function parseConfigPragmaEnvironmentForTest(
const maybeConfig: any = {};
// Get the defaults to programmatically check for boolean properties
const defaultConfig = EnvironmentConfigSchema.parse({});
(maybeConfig as PartialEnvironmentConfig).enableEmitHookGuards = null;
for (const token of pragma.split(' ')) {
if (!token.startsWith('@')) {
@@ -1148,9 +1126,32 @@ export class Environment {
);
}
getFallthroughPropertyType(
receiver: Type,
_property: Type,
): BuiltInType | PolyType | null {
let shapeId = null;
if (receiver.kind === 'Object' || receiver.kind === 'Function') {
shapeId = receiver.shapeId;
}
if (shapeId !== null) {
const shape = this.#shapes.get(shapeId);
CompilerError.invariant(shape !== undefined, {
reason: `[HIR] Forget internal error: cannot resolve shape ${shapeId}`,
description: null,
loc: null,
suggestions: null,
});
return shape.properties.get('*') ?? null;
}
return null;
}
getPropertyType(
receiver: Type,
property: string,
property: string | number,
): BuiltInType | PolyType | null {
let shapeId = null;
if (receiver.kind === 'Object' || receiver.kind === 'Function') {
@@ -1168,17 +1169,19 @@ export class Environment {
loc: null,
suggestions: null,
});
let value =
shape.properties.get(property) ?? shape.properties.get('*') ?? null;
if (value === null && isHookName(property)) {
value = this.#getCustomHookType();
if (typeof property === 'string') {
return (
shape.properties.get(property) ??
shape.properties.get('*') ??
(isHookName(property) ? this.#getCustomHookType() : null)
);
} else {
return shape.properties.get('*') ?? null;
}
return value;
} else if (isHookName(property)) {
} else if (typeof property === 'string' && isHookName(property)) {
return this.#getCustomHookType();
} else {
return null;
}
return null;
}
getFunctionSignature(type: FunctionType): FunctionSignature | null {

View File

@@ -63,8 +63,20 @@ export function findContextIdentifiers(
state: FindContextIdentifierState,
): void {
const left = path.get('left');
const currentFn = state.currentFn.at(-1) ?? null;
handleAssignment(currentFn, state.identifiers, left);
if (left.isLVal()) {
const currentFn = state.currentFn.at(-1) ?? null;
handleAssignment(currentFn, state.identifiers, left);
} else {
/**
* OptionalMemberExpressions as the left side of an AssignmentExpression are Stage 1 and
* not supported by React Compiler yet.
*/
CompilerError.throwTodo({
reason: `Unsupported syntax on the left side of an AssignmentExpression`,
description: `Expected an LVal, got: ${left.type}`,
loc: left.node.loc ?? null,
});
}
},
UpdateExpression(
path: NodePath<t.UpdateExpression>,

View File

@@ -119,8 +119,8 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [
],
/*
* https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.from
* Array.from(arrayLike, optionalFn, optionalThis) not added because
* the Effect of `arrayLike` is polymorphic i.e.
* Array.from(arrayLike, optionalFn, optionalThis)
* Note that the Effect of `arrayLike` is polymorphic i.e.
* - Effect.read if
* - it does not have an @iterator property and is array-like
* (i.e. has a length property)
@@ -128,6 +128,20 @@ const TYPED_GLOBALS: Array<[string, BuiltInType]> = [
* - Effect.mutate if it is a self-mutative iterator (e.g. a generator
* function)
*/
[
'from',
addFunction(DEFAULT_SHAPES, [], {
positionalParams: [
Effect.ConditionallyMutate,
Effect.ConditionallyMutate,
Effect.ConditionallyMutate,
],
restParam: Effect.Read,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Mutable,
}),
],
[
'of',
// Array.of(element0, ..., elementN)

View File

@@ -535,6 +535,30 @@ addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
['*', {kind: 'Object', shapeId: BuiltInRefValueId}],
]);
/**
* MixedReadOnly =
* | primitive
* | simple objects (Record<string, MixedReadOnly>)
* | Array<MixedReadOnly>
*
* APIs such as Relay — but also Flux and other data stores — often return a
* union of types with some interesting properties in terms of analysis.
*
* Given this constraint, if data came from Relay, then we should be able to
* infer things like `data.items.map(): Array`. That may seem like a leap at
* first but remember, we assume you're not patching builtins. Thus the only way
* data.items.map can exist and be a function, given the above set of data types
* and builtin JS methods, is if `data.items` was an Array, and `data.items.map`
* is therefore calling Array.prototype.map. Then we know that function returns
* an Array as well. This relies on the fact that map() is being called, so if
* data.items was some other type it would error at runtime - so it's sound.
*
* Note that this shape is currently only used for hook return values, which
* means that it's safe to type aliasing method-call return kinds as `Frozen`.
*
* Also note that all newly created arrays from method-calls (e.g. `.map`)
* have the appropriate mutable `BuiltInArray` shape
*/
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
[
'toString',
@@ -546,6 +570,36 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
returnValueKind: ValueKind.Primitive,
}),
],
[
'indexOf',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'Primitive'},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'includes',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'Primitive'},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'at',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [Effect.Read],
restParam: null,
returnType: {kind: 'Object', shapeId: BuiltInMixedReadonlyId},
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Frozen,
}),
],
[
'map',
addFunction(BUILTIN_SHAPES, [], {
@@ -642,9 +696,9 @@ addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Poly'},
returnType: {kind: 'Object', shapeId: BuiltInMixedReadonlyId},
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
returnValueKind: ValueKind.Frozen,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),

View File

@@ -60,7 +60,15 @@ export type PropType = {
kind: 'Property';
objectType: Type;
objectName: string;
propertyName: PropertyLiteral;
propertyName:
| {
kind: 'literal';
value: PropertyLiteral;
}
| {
kind: 'computed';
value: Type;
};
};
export type ObjectMethod = {

View File

@@ -872,11 +872,33 @@ function inferBlock(
reason: new Set([ValueReason.Other]),
context: new Set(),
};
for (const element of instrValue.elements) {
if (element.kind === 'Spread') {
state.referenceAndRecordEffects(
freezeActions,
element.place,
isArrayType(element.place.identifier)
? Effect.Capture
: Effect.ConditionallyMutate,
ValueReason.Other,
);
} else if (element.kind === 'Identifier') {
state.referenceAndRecordEffects(
freezeActions,
element,
Effect.Capture,
ValueReason.Other,
);
} else {
let _: 'Hole' = element.kind;
}
}
state.initialize(instrValue, valueKind);
state.define(instr.lvalue, instrValue);
instr.lvalue.effect = Effect.Store;
continuation = {
kind: 'initialize',
valueKind,
effect: {kind: Effect.Capture, reason: ValueReason.Other},
lvalueEffect: Effect.Store,
kind: 'funeffects',
};
break;
}
@@ -1241,21 +1263,12 @@ function inferBlock(
for (let i = 0; i < instrValue.args.length; i++) {
const arg = instrValue.args[i];
const place = arg.kind === 'Identifier' ? arg : arg.place;
if (effects !== null) {
state.referenceAndRecordEffects(
freezeActions,
place,
effects[i],
ValueReason.Other,
);
} else {
state.referenceAndRecordEffects(
freezeActions,
place,
Effect.ConditionallyMutate,
ValueReason.Other,
);
}
state.referenceAndRecordEffects(
freezeActions,
place,
getArgumentEffect(effects != null ? effects[i] : null, arg),
ValueReason.Other,
);
hasCaptureArgument ||= place.effect === Effect.Capture;
}
if (signature !== null) {
@@ -1307,7 +1320,10 @@ function inferBlock(
signature !== null
? {
kind: signature.returnValueKind,
reason: new Set([ValueReason.Other]),
reason: new Set([
signature.returnValueReason ??
ValueReason.KnownReturnSignature,
]),
context: new Set(),
}
: {
@@ -1356,25 +1372,16 @@ function inferBlock(
for (let i = 0; i < instrValue.args.length; i++) {
const arg = instrValue.args[i];
const place = arg.kind === 'Identifier' ? arg : arg.place;
if (effects !== null) {
/*
* If effects are inferred for an argument, we should fail invalid
* mutating effects
*/
state.referenceAndRecordEffects(
freezeActions,
place,
effects[i],
ValueReason.Other,
);
} else {
state.referenceAndRecordEffects(
freezeActions,
place,
Effect.ConditionallyMutate,
ValueReason.Other,
);
}
/*
* If effects are inferred for an argument, we should fail invalid
* mutating effects
*/
state.referenceAndRecordEffects(
freezeActions,
place,
getArgumentEffect(effects != null ? effects[i] : null, arg),
ValueReason.Other,
);
hasCaptureArgument ||= place.effect === Effect.Capture;
}
if (signature !== null) {
@@ -2049,3 +2056,31 @@ function areArgumentsImmutableAndNonMutating(
}
return true;
}
function getArgumentEffect(
signatureEffect: Effect | null,
arg: Place | SpreadPattern,
): Effect {
if (signatureEffect != null) {
if (arg.kind === 'Identifier') {
return signatureEffect;
} else if (
signatureEffect === Effect.Mutate ||
signatureEffect === Effect.ConditionallyMutate
) {
return signatureEffect;
} else {
// see call-spread-argument-mutable-iterator test fixture
if (signatureEffect === Effect.Freeze) {
CompilerError.throwTodo({
reason: 'Support spread syntax for hook arguments',
loc: arg.place.loc,
});
}
// effects[i] is Effect.Capture | Effect.Read | Effect.Store
return Effect.ConditionallyMutate;
}
} else {
return Effect.ConditionallyMutate;
}
}

View File

@@ -178,11 +178,15 @@ function mergeLocation(l: SourceLocation, r: SourceLocation): SourceLocation {
return l;
} else {
return {
filename: l.filename,
identifierName: l.identifierName,
start: {
index: Math.min(l.start.index, r.start.index),
line: Math.min(l.start.line, r.start.line),
column: Math.min(l.start.column, r.start.column),
},
end: {
index: Math.max(l.end.index, r.end.index),
line: Math.max(l.end.line, r.end.line),
column: Math.max(l.end.column, r.end.column),
},
@@ -202,7 +206,7 @@ export function inRange(
return id >= range.start && id < range.end;
}
function mayAllocate(env: Environment, instruction: Instruction): boolean {
function mayAllocate(_env: Environment, instruction: Instruction): boolean {
const {value} = instruction;
switch (value.kind) {
case 'Destructure': {

View File

@@ -307,11 +307,26 @@ function* generateInstructionTypes(
kind: 'Property',
objectType: value.object.identifier.type,
objectName: getName(names, value.object.identifier.id),
propertyName: value.property,
propertyName: {
kind: 'literal',
value: value.property,
},
});
break;
}
case 'ComputedLoad': {
yield equation(left, {
kind: 'Property',
objectType: value.object.identifier.type,
objectName: getName(names, value.object.identifier.id),
propertyName: {
kind: 'computed',
value: value.property.identifier.type,
},
});
break;
}
case 'MethodCall': {
const returnType = makeType();
yield equation(value.property.identifier.type, {
@@ -336,7 +351,10 @@ function* generateInstructionTypes(
kind: 'Property',
objectType: value.value.identifier.type,
objectName: getName(names, value.value.identifier.id),
propertyName: makePropertyLiteral(propertyName),
propertyName: {
kind: 'literal',
value: makePropertyLiteral(propertyName),
},
});
} else {
break;
@@ -353,7 +371,10 @@ function* generateInstructionTypes(
kind: 'Property',
objectType: value.value.identifier.type,
objectName: getName(names, value.value.identifier.id),
propertyName: makePropertyLiteral(property.key.name),
propertyName: {
kind: 'literal',
value: makePropertyLiteral(property.key.name),
},
});
}
}
@@ -410,7 +431,6 @@ function* generateInstructionTypes(
case 'RegExpLiteral':
case 'MetaProperty':
case 'ComputedStore':
case 'ComputedLoad':
case 'Await':
case 'GetIterator':
case 'IteratorNext':
@@ -454,12 +474,13 @@ class Unifier {
return;
}
const objectType = this.get(tB.objectType);
let propertyType;
if (typeof tB.propertyName === 'number') {
propertyType = null;
} else {
propertyType = this.env.getPropertyType(objectType, tB.propertyName);
}
const propertyType =
tB.propertyName.kind === 'literal'
? this.env.getPropertyType(objectType, tB.propertyName.value)
: this.env.getFallthroughPropertyType(
objectType,
tB.propertyName.value,
);
if (propertyType !== null) {
this.unify(tA, propertyType);
}
@@ -677,7 +698,11 @@ class Unifier {
const RefLikeNameRE = /^(?:[a-zA-Z$_][a-zA-Z$_0-9]*)Ref$|^ref$/;
function isRefLikeName(t: PropType): boolean {
return RefLikeNameRE.test(t.objectName) && t.propertyName === 'current';
return (
t.propertyName.kind === 'literal' &&
RefLikeNameRE.test(t.objectName) &&
t.propertyName.value === 'current'
);
}
function tryUnionTypes(ty1: Type, ty2: Type): Type | null {

View File

@@ -0,0 +1,91 @@
## Input
```javascript
import {useIdentity, Stringify} from 'shared-runtime';
/**
* TODO: Note that this `Array.from` is inferred to be mutating its first
* argument. This is because React Compiler's typing system does not yet support
* annotating a function with a set of argument match cases + distinct
* definitions (polymorphism).
*
* In this case, we should be able to infer that the `Array.from` call is
* not mutating its 0th argument.
* The 0th argument should be typed as having `effect:Mutate` only when
* (1) it might be a mutable iterable or
* (2) the 1st argument might mutate its callee
*/
function Component({value}) {
const arr = [{value: 'foo'}, {value: 'bar'}, {value}];
useIdentity();
const derived = Array.from(arr, (x, idx) => ({...x, id: idx}));
return <Stringify>{derived.at(-1)}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 5}],
sequentialRenders: [{value: 5}, {value: 6}, {value: 6}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { useIdentity, Stringify } from "shared-runtime";
/**
* TODO: Note that this `Array.from` is inferred to be mutating its first
* argument. This is because React Compiler's typing system does not yet support
* annotating a function with a set of argument match cases + distinct
* definitions (polymorphism).
*
* In this case, we should be able to infer that the `Array.from` call is
* not mutating its 0th argument.
* The 0th argument should be typed as having `effect:Mutate` only when
* (1) it might be a mutable iterable or
* (2) the 1st argument might mutate its callee
*/
function Component(t0) {
const $ = _c(4);
const { value } = t0;
const arr = [{ value: "foo" }, { value: "bar" }, { value }];
useIdentity();
const derived = Array.from(arr, _temp);
let t1;
if ($[0] !== derived) {
t1 = derived.at(-1);
$[0] = derived;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== t1) {
t2 = <Stringify>{t1}</Stringify>;
$[2] = t1;
$[3] = t2;
} else {
t2 = $[3];
}
return t2;
}
function _temp(x, idx) {
return { ...x, id: idx };
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ value: 5 }],
sequentialRenders: [{ value: 5 }, { value: 6 }, { value: 6 }],
};
```
### Eval output
(kind: ok) <div>{"children":{"value":5,"id":2}}</div>
<div>{"children":{"value":6,"id":2}}</div>
<div>{"children":{"value":6,"id":2}}</div>

View File

@@ -0,0 +1,26 @@
import {useIdentity, Stringify} from 'shared-runtime';
/**
* TODO: Note that this `Array.from` is inferred to be mutating its first
* argument. This is because React Compiler's typing system does not yet support
* annotating a function with a set of argument match cases + distinct
* definitions (polymorphism).
*
* In this case, we should be able to infer that the `Array.from` call is
* not mutating its 0th argument.
* The 0th argument should be typed as having `effect:Mutate` only when
* (1) it might be a mutable iterable or
* (2) the 1st argument might mutate its callee
*/
function Component({value}) {
const arr = [{value: 'foo'}, {value: 'bar'}, {value}];
useIdentity();
const derived = Array.from(arr, (x, idx) => ({...x, id: idx}));
return <Stringify>{derived.at(-1)}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 5}],
sequentialRenders: [{value: 5}, {value: 6}, {value: 6}],
};

View File

@@ -0,0 +1,88 @@
## Input
```javascript
import {useIdentity, Stringify} from 'shared-runtime';
/**
* TODO: Note that this `Array.from` is inferred to be mutating its first
* argument. This is because React Compiler's typing system does not yet support
* annotating a function with a set of argument match cases + distinct
* definitions (polymorphism)
*
* In this case, we should be able to infer that the `Array.from` call is
* not mutating its 0th argument.
* The 0th argument should be typed as having `effect:Mutate` only when
* (1) it might be a mutable iterable or
* (2) the 1st argument might mutate its callee
*/
function Component({value}) {
const arr = [{value: 'foo'}, {value: 'bar'}, {value}];
useIdentity();
const derived = Array.from(arr);
return <Stringify>{derived.at(-1)}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 5}],
sequentialRenders: [{value: 5}, {value: 6}, {value: 6}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { useIdentity, Stringify } from "shared-runtime";
/**
* TODO: Note that this `Array.from` is inferred to be mutating its first
* argument. This is because React Compiler's typing system does not yet support
* annotating a function with a set of argument match cases + distinct
* definitions (polymorphism)
*
* In this case, we should be able to infer that the `Array.from` call is
* not mutating its 0th argument.
* The 0th argument should be typed as having `effect:Mutate` only when
* (1) it might be a mutable iterable or
* (2) the 1st argument might mutate its callee
*/
function Component(t0) {
const $ = _c(4);
const { value } = t0;
const arr = [{ value: "foo" }, { value: "bar" }, { value }];
useIdentity();
const derived = Array.from(arr);
let t1;
if ($[0] !== derived) {
t1 = derived.at(-1);
$[0] = derived;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== t1) {
t2 = <Stringify>{t1}</Stringify>;
$[2] = t1;
$[3] = t2;
} else {
t2 = $[3];
}
return t2;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ value: 5 }],
sequentialRenders: [{ value: 5 }, { value: 6 }, { value: 6 }],
};
```
### Eval output
(kind: ok) <div>{"children":{"value":5}}</div>
<div>{"children":{"value":6}}</div>
<div>{"children":{"value":6}}</div>

View File

@@ -0,0 +1,26 @@
import {useIdentity, Stringify} from 'shared-runtime';
/**
* TODO: Note that this `Array.from` is inferred to be mutating its first
* argument. This is because React Compiler's typing system does not yet support
* annotating a function with a set of argument match cases + distinct
* definitions (polymorphism)
*
* In this case, we should be able to infer that the `Array.from` call is
* not mutating its 0th argument.
* The 0th argument should be typed as having `effect:Mutate` only when
* (1) it might be a mutable iterable or
* (2) the 1st argument might mutate its callee
*/
function Component({value}) {
const arr = [{value: 'foo'}, {value: 'bar'}, {value}];
useIdentity();
const derived = Array.from(arr);
return <Stringify>{derived.at(-1)}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 5}],
sequentialRenders: [{value: 5}, {value: 6}, {value: 6}],
};

View File

@@ -0,0 +1,64 @@
## Input
```javascript
import {mutateAndReturn, Stringify, useIdentity} from 'shared-runtime';
function Component({value}) {
const arr = [{value: 'foo'}, {value: 'bar'}, {value}];
useIdentity();
const derived = Array.from(arr, mutateAndReturn);
return <Stringify>{derived.at(-1)}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 5}],
sequentialRenders: [{value: 5}, {value: 6}, {value: 6}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { mutateAndReturn, Stringify, useIdentity } from "shared-runtime";
function Component(t0) {
const $ = _c(4);
const { value } = t0;
const arr = [{ value: "foo" }, { value: "bar" }, { value }];
useIdentity();
const derived = Array.from(arr, mutateAndReturn);
let t1;
if ($[0] !== derived) {
t1 = derived.at(-1);
$[0] = derived;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== t1) {
t2 = <Stringify>{t1}</Stringify>;
$[2] = t1;
$[3] = t2;
} else {
t2 = $[3];
}
return t2;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{ value: 5 }],
sequentialRenders: [{ value: 5 }, { value: 6 }, { value: 6 }],
};
```
### Eval output
(kind: ok) <div>{"children":{"value":5,"wat0":"joe"}}</div>
<div>{"children":{"value":6,"wat0":"joe"}}</div>
<div>{"children":{"value":6,"wat0":"joe"}}</div>

View File

@@ -0,0 +1,14 @@
import {mutateAndReturn, Stringify, useIdentity} from 'shared-runtime';
function Component({value}) {
const arr = [{value: 'foo'}, {value: 'bar'}, {value}];
useIdentity();
const derived = Array.from(arr, mutateAndReturn);
return <Stringify>{derived.at(-1)}</Stringify>;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{value: 5}],
sequentialRenders: [{value: 5}, {value: 6}, {value: 6}],
};

View File

@@ -0,0 +1,62 @@
## Input
```javascript
function useBar({arg}) {
/**
* Note that mutableIterator is mutated by the later object spread. Therefore,
* `s.values()` should be memoized within the same block as the object spread.
* In terms of compiler internals, they should have the same reactive scope.
*/
const obj = {};
const s = new Set([obj, 5, 4]);
const mutableIterator = s.values();
const arr = [...mutableIterator];
obj.x = arg;
return arr;
}
export const FIXTURE_ENTRYPOINT = {
fn: useBar,
params: [{arg: 3}],
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
function useBar(t0) {
const $ = _c(2);
const { arg } = t0;
let arr;
if ($[0] !== arg) {
const obj = {};
const s = new Set([obj, 5, 4]);
const mutableIterator = s.values();
arr = [...mutableIterator];
obj.x = arg;
$[0] = arg;
$[1] = arr;
} else {
arr = $[1];
}
return arr;
}
export const FIXTURE_ENTRYPOINT = {
fn: useBar,
params: [{ arg: 3 }],
sequentialRenders: [{ arg: 3 }, { arg: 3 }, { arg: 4 }],
};
```
### Eval output
(kind: ok) [{"x":3},5,4]
[{"x":3},5,4]
[{"x":4},5,4]

View File

@@ -0,0 +1,20 @@
function useBar({arg}) {
/**
* Note that mutableIterator is mutated by the later object spread. Therefore,
* `s.values()` should be memoized within the same block as the object spread.
* In terms of compiler internals, they should have the same reactive scope.
*/
const obj = {};
const s = new Set([obj, 5, 4]);
const mutableIterator = s.values();
const arr = [...mutableIterator];
obj.x = arg;
return arr;
}
export const FIXTURE_ENTRYPOINT = {
fn: useBar,
params: [{arg: 3}],
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
};

View File

@@ -0,0 +1,85 @@
## Input
```javascript
/**
* TODO: object spreads should have conditionally mutate semantics
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [3,1,5,4]
* [3,1,5,4]
* [4,1,5,4]
* Forget:
* (kind: ok) [3,1,5,4]
* [3,1,5,4]
* [4]
*/
function useBar({arg}) {
'use memo';
/**
* Note that mutableIterator is mutated by the later object spread. Therefore,
* `s.values()` should be memoized within the same block as the object spread.
* In terms of compiler internals, they should have the same reactive scope.
*/
const s = new Set([1, 5, 4]);
const mutableIterator = s.values();
return [arg, ...mutableIterator];
}
export const FIXTURE_ENTRYPOINT = {
fn: useBar,
params: [{arg: 3}],
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime"; /**
* TODO: object spreads should have conditionally mutate semantics
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [3,1,5,4]
* [3,1,5,4]
* [4,1,5,4]
* Forget:
* (kind: ok) [3,1,5,4]
* [3,1,5,4]
* [4]
*/
function useBar(t0) {
"use memo";
const $ = _c(2);
const { arg } = t0;
let t1;
if ($[0] !== arg) {
const s = new Set([1, 5, 4]);
const mutableIterator = s.values();
t1 = [arg, ...mutableIterator];
$[0] = arg;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: useBar,
params: [{ arg: 3 }],
sequentialRenders: [{ arg: 3 }, { arg: 3 }, { arg: 4 }],
};
```
### Eval output
(kind: ok) [3,1,5,4]
[3,1,5,4]
[4,1,5,4]

View File

@@ -0,0 +1,32 @@
/**
* TODO: object spreads should have conditionally mutate semantics
* Found differences in evaluator results
* Non-forget (expected):
* (kind: ok) [3,1,5,4]
* [3,1,5,4]
* [4,1,5,4]
* Forget:
* (kind: ok) [3,1,5,4]
* [3,1,5,4]
* [4]
*/
function useBar({arg}) {
'use memo';
/**
* Note that mutableIterator is mutated by the later object spread. Therefore,
* `s.values()` should be memoized within the same block as the object spread.
* In terms of compiler internals, they should have the same reactive scope.
*/
const s = new Set([1, 5, 4]);
const mutableIterator = s.values();
return [arg, ...mutableIterator];
}
export const FIXTURE_ENTRYPOINT = {
fn: useBar,
params: [{arg: 3}],
sequentialRenders: [{arg: 3}, {arg: 3}, {arg: 4}],
};

View File

@@ -1,35 +0,0 @@
## Input
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export default ErrorView;
```
## Code
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
$[0] = error;
$[1] = t0;
} else {
t0 = $[1];
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
export default ErrorView;
```

View File

@@ -1,4 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export default ErrorView;

View File

@@ -0,0 +1,42 @@
## Input
```javascript
import {useIdentity} from 'shared-runtime';
function useFoo() {
const it = new Set([1, 2]).values();
useIdentity();
return Math.max(...it);
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{}],
sequentialRenders: [{}, {}],
};
```
## Code
```javascript
import { useIdentity } from "shared-runtime";
function useFoo() {
const it = new Set([1, 2]).values();
useIdentity();
return Math.max(...it);
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{}],
sequentialRenders: [{}, {}],
};
```
### Eval output
(kind: ok) 2
2

View File

@@ -0,0 +1,13 @@
import {useIdentity} from 'shared-runtime';
function useFoo() {
const it = new Set([1, 2]).values();
useIdentity();
return Math.max(...it);
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{}],
sequentialRenders: [{}, {}],
};

View File

@@ -21,7 +21,7 @@ import {
import { c as _c } from "react/compiler-runtime"; // @enableEmitFreeze @enableEmitInstrumentForget
function useFoo(props) {
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("useFoo", "/codegen-emit-imports-same-source.ts");
const $ = _c(2);
let t0;

View File

@@ -28,7 +28,7 @@ import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget
function Bar(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Bar", "/codegen-instrument-forget-test.ts");
const $ = _c(2);
let t0;
@@ -48,7 +48,7 @@ function NoForget(props) {
function Foo(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Foo", "/codegen-instrument-forget-test.ts");
const $ = _c(2);
let t0;

View File

@@ -0,0 +1,33 @@
## Input
```javascript
import {useIdentity} from 'shared-runtime';
function Component() {
const items = makeArray(0, 1, 2, null, 4, false, 6);
return useIdentity(...items.values());
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
sequentialRenders: [{}, {}],
};
```
## Error
```
3 | function Component() {
4 | const items = makeArray(0, 1, 2, null, 4, false, 6);
> 5 | return useIdentity(...items.values());
| ^^^^^^^^^^^^^^ Todo: Support spread syntax for hook arguments (5:5)
6 | }
7 |
8 | export const FIXTURE_ENTRYPOINT = {
```

View File

@@ -0,0 +1,12 @@
import {useIdentity} from 'shared-runtime';
function Component() {
const items = makeArray(0, 1, 2, null, 4, false, 6);
return useIdentity(...items.values());
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [],
sequentialRenders: [{}, {}],
};

View File

@@ -4,9 +4,10 @@
```javascript
import {makeArray} from 'shared-runtime';
function Component(props) {
const other = [0, 1];
function Component({}) {
const items = makeArray(0, 1, 2, null, 4, false, 6);
const max = Math.max(...items.filter(Boolean));
const max = Math.max(2, items.push(5), ...other);
return max;
}
@@ -21,13 +22,13 @@ export const FIXTURE_ENTRYPOINT = {
## Error
```
3 | function Component(props) {
4 | const items = makeArray(0, 1, 2, null, 4, false, 6);
> 5 | const max = Math.max(...items.filter(Boolean));
| ^^^^^^^^ Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` (5:5)
6 | return max;
7 | }
8 |
4 | function Component({}) {
5 | const items = makeArray(0, 1, 2, null, 4, false, 6);
> 6 | const max = Math.max(2, items.push(5), ...other);
| ^^^^^^^^ Invariant: [Codegen] Internal error: MethodCall::property must be an unpromoted + unmemoized MemberExpression. Got a `Identifier` (6:6)
7 | return max;
8 | }
9 |
```

View File

@@ -1,8 +1,9 @@
import {makeArray} from 'shared-runtime';
function Component(props) {
const other = [0, 1];
function Component({}) {
const items = makeArray(0, 1, 2, null, 4, false, 6);
const max = Math.max(...items.filter(Boolean));
const max = Math.max(2, items.push(5), ...other);
return max;
}

View File

@@ -1,14 +0,0 @@
// @gating @compilationMode(annotation)
export default function Bar(props) {
'use forget';
return <div>{props.bar}</div>;
}
function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
export function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}

View File

@@ -0,0 +1,50 @@
## Input
```javascript
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = ({error, _retry}) => <Stringify error={error}></Stringify>;
export default ErrorView;
export const FIXTURE_ENTRYPOINT = {
fn: eval('ErrorView'),
params: [{}],
};
```
## Code
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (t0) => {
const $ = _c(2);
const { error } = t0;
let t1;
if ($[0] !== error) {
t1 = <Stringify error={error} />;
$[0] = error;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
: ({ error, _retry }) => <Stringify error={error}></Stringify>;
export default ErrorView;
export const FIXTURE_ENTRYPOINT = {
fn: eval("ErrorView"),
params: [{}],
};
```
### Eval output
(kind: ok) <div>{}</div>

View File

@@ -0,0 +1,10 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = ({error, _retry}) => <Stringify error={error}></Stringify>;
export default ErrorView;
export const FIXTURE_ENTRYPOINT = {
fn: eval('ErrorView'),
params: [{}],
};

View File

@@ -15,9 +15,22 @@ function NoForget(props) {
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
global.DEV = true;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Foo'),
params: [{bar: 2}],
};
```
## Code
@@ -29,7 +42,7 @@ import { c as _c } from "react/compiler-runtime"; // @enableEmitInstrumentForget
const Bar = isForgetEnabled_Fixtures()
? function Bar(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Bar", "/codegen-instrument-forget-gating-test.ts");
const $ = _c(2);
let t0;
@@ -53,23 +66,50 @@ function NoForget(props) {
const Foo = isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
if (__DEV__ && shouldInstrument)
if (DEV && shouldInstrument)
useRenderCounter("Foo", "/codegen-instrument-forget-gating-test.ts");
const $ = _c(2);
let t0;
if ($[0] !== props.bar) {
t0 = <Foo>{props.bar}</Foo>;
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
const $ = _c(3);
if (props.bar < 0) {
return props.children;
}
return t0;
const t0 = props.bar - 1;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <NoForget />;
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== t0) {
t2 = <Foo bar={t0}>{t1}</Foo>;
$[1] = t0;
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
: function Foo(props) {
"use forget";
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
};
global.DEV = true;
export const FIXTURE_ENTRYPOINT = {
fn: eval("Foo"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div></div>

View File

@@ -11,5 +11,18 @@ function NoForget(props) {
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
global.DEV = true;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Foo'),
params: [{bar: 2}],
};

View File

@@ -17,6 +17,11 @@ function Foo(props) {
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -66,5 +71,12 @@ const Foo = isForgetEnabled_Fixtures()
return <Foo>{props.bar}</Foo>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -12,3 +12,8 @@ function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -12,11 +12,23 @@ function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
export function Foo(props) {
function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -47,25 +59,50 @@ export default Bar;
function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
export const Foo = isForgetEnabled_Fixtures()
const Foo = isForgetEnabled_Fixtures()
? function Foo(props) {
"use forget";
const $ = _c(2);
let t0;
if ($[0] !== props.bar) {
t0 = <Foo>{props.bar}</Foo>;
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
const $ = _c(3);
if (props.bar < 0) {
return props.children;
}
return t0;
const t0 = props.bar - 1;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <NoForget />;
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== t0) {
t2 = <Foo bar={t0}>{t1}</Foo>;
$[1] = t0;
$[2] = t2;
} else {
t2 = $[2];
}
return t2;
}
: function Foo(props) {
"use forget";
return <Foo>{props.bar}</Foo>;
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -0,0 +1,26 @@
// @gating @compilationMode(annotation)
export default function Bar(props) {
'use forget';
return <div>{props.bar}</div>;
}
function NoForget(props) {
return <Bar>{props.noForget}</Bar>;
}
function Foo(props) {
'use forget';
if (props.bar < 0) {
return props.children;
}
return (
<Foo bar={props.bar - 1}>
<NoForget />
</Foo>
);
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -17,6 +17,11 @@ export function Foo(props) {
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -66,5 +71,12 @@ export const Foo = isForgetEnabled_Fixtures()
return <Foo>{props.bar}</Foo>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -12,3 +12,8 @@ export function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -17,6 +17,11 @@ function Foo(props) {
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};
```
## Code
@@ -65,5 +70,12 @@ const Foo = isForgetEnabled_Fixtures()
return <Foo>{props.bar}</Foo>;
};
export const FIXTURE_ENTRYPOINT = {
fn: eval("Bar"),
params: [{ bar: 2 }],
};
```
### Eval output
(kind: ok) <div>2</div>

View File

@@ -12,3 +12,8 @@ function Foo(props) {
'use forget';
return <Foo>{props.bar}</Foo>;
}
export const FIXTURE_ENTRYPOINT = {
fn: eval('Bar'),
params: [{bar: 2}],
};

View File

@@ -13,6 +13,11 @@ component Component(value: string) {
export default memo<Props>(Component);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Component'),
params: [{value: 'foo'}],
};
```
## Code
@@ -43,5 +48,12 @@ const Component = isForgetEnabled_Fixtures()
export default memo<Props>(Component);
export const FIXTURE_ENTRYPOINT = {
fn: eval("Component"),
params: [{ value: "foo" }],
};
```
### Eval output
(kind: ok) <div>foo</div>

View File

@@ -8,3 +8,8 @@ component Component(value: string) {
}
export default memo<Props>(Component);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Component'),
params: [{value: 'foo'}],
};

View File

@@ -35,4 +35,7 @@ export default React.forwardRef(
);
```
### Eval output
(kind: exception) Fixture not implemented
logs: ['forwardRef render functions accept exactly two parameters: props and ref. %s','Did you forget to use the ref parameter?']

View File

@@ -3,17 +3,17 @@
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
import {Stringify} from 'shared-runtime';
const Renderer = props => (
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export default props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);
export default Renderer;
```
## Code
@@ -21,12 +21,14 @@ export default Renderer;
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
t0 = <Stringify error={error} />;
$[0] = error;
$[1] = t0;
} else {
@@ -34,9 +36,9 @@ const ErrorView = isForgetEnabled_Fixtures()
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
: (error, _retry) => <Stringify error={error}></Stringify>;
const Renderer = isForgetEnabled_Fixtures()
export default isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
@@ -59,7 +61,8 @@ const Renderer = isForgetEnabled_Fixtures()
<ErrorView></ErrorView>
</Foo>
);
export default Renderer;
```
### Eval output
(kind: exception) Fixture not implemented

View File

@@ -0,0 +1,11 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export default props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);

View File

@@ -3,15 +3,22 @@
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export const Renderer = props => (
<Foo>
<Bar></Bar>
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};
```
## Code
@@ -19,12 +26,14 @@ export const Renderer = props => (
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
t0 = <Stringify error={error} />;
$[0] = error;
$[1] = t0;
} else {
@@ -32,7 +41,7 @@ const ErrorView = isForgetEnabled_Fixtures()
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
: (error, _retry) => <Stringify error={error}></Stringify>;
export const Renderer = isForgetEnabled_Fixtures()
? (props) => {
@@ -40,10 +49,10 @@ export const Renderer = isForgetEnabled_Fixtures()
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<Foo>
<Bar />
<div>
<span />
<ErrorView />
</Foo>
</div>
);
$[0] = t0;
} else {
@@ -52,11 +61,17 @@ export const Renderer = isForgetEnabled_Fixtures()
return t0;
}
: (props) => (
<Foo>
<Bar></Bar>
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export const FIXTURE_ENTRYPOINT = {
fn: eval("Renderer"),
params: [{}],
};
```
### Eval output
(kind: ok) <div><span></span><div>{"error":{}}</div></div>

View File

@@ -0,0 +1,16 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
export const Renderer = props => (
<div>
<span></span>
<ErrorView></ErrorView>
</div>
);
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};

View File

@@ -3,15 +3,24 @@
```javascript
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
import {Stringify} from 'shared-runtime';
export default Renderer = props => (
<Foo>
<Bar></Bar>
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
const Renderer = props => (
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export default Renderer;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};
```
## Code
@@ -19,12 +28,14 @@ export default Renderer = props => (
```javascript
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
import { c as _c } from "react/compiler-runtime"; // @gating
import { Stringify } from "shared-runtime";
const ErrorView = isForgetEnabled_Fixtures()
? (error, _retry) => {
const $ = _c(2);
let t0;
if ($[0] !== error) {
t0 = <MessageBox error={error} />;
t0 = <Stringify error={error} />;
$[0] = error;
$[1] = t0;
} else {
@@ -32,18 +43,18 @@ const ErrorView = isForgetEnabled_Fixtures()
}
return t0;
}
: (error, _retry) => <MessageBox error={error}></MessageBox>;
: (error, _retry) => <Stringify error={error}></Stringify>;
export default Renderer = isForgetEnabled_Fixtures()
const Renderer = isForgetEnabled_Fixtures()
? (props) => {
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = (
<Foo>
<Bar />
<div>
<span />
<ErrorView />
</Foo>
</div>
);
$[0] = t0;
} else {
@@ -52,11 +63,19 @@ export default Renderer = isForgetEnabled_Fixtures()
return t0;
}
: (props) => (
<Foo>
<Bar></Bar>
<div>
<span></span>
<ErrorView></ErrorView>
</Foo>
</div>
);
export default Renderer;
export const FIXTURE_ENTRYPOINT = {
fn: eval("Renderer"),
params: [{}],
};
```
### Eval output
(kind: ok) <div><span></span><div>{"error":{}}</div></div>

View File

@@ -0,0 +1,18 @@
// @gating
import {Stringify} from 'shared-runtime';
const ErrorView = (error, _retry) => <Stringify error={error}></Stringify>;
const Renderer = props => (
<div>
<span></span>
<ErrorView></ErrorView>
</div>
);
export default Renderer;
export const FIXTURE_ENTRYPOINT = {
fn: eval('Renderer'),
params: [{}],
};

View File

@@ -1,9 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export default Renderer = props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);

View File

@@ -1,9 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
export const Renderer = props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);

View File

@@ -1,11 +0,0 @@
// @gating
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
const Renderer = props => (
<Foo>
<Bar></Bar>
<ErrorView></ErrorView>
</Foo>
);
export default Renderer;

View File

@@ -0,0 +1,61 @@
## Input
```javascript
import {useFragment} from 'shared-runtime';
/**
* React compiler should infer that the returned value is a primitive and avoid
* memoizing it.
*/
function useRelayData({query, idx}) {
'use memo';
const data = useFragment('', query);
return data.a[idx].toString();
}
export const FIXTURE_ENTRYPOINT = {
fn: useRelayData,
params: [{query: '', idx: 0}],
sequentialRenders: [
{query: '', idx: 0},
{query: '', idx: 0},
{query: '', idx: 1},
],
};
```
## Code
```javascript
import { useFragment } from "shared-runtime";
/**
* React compiler should infer that the returned value is a primitive and avoid
* memoizing it.
*/
function useRelayData(t0) {
"use memo";
const { query, idx } = t0;
const data = useFragment("", query);
return data.a[idx].toString();
}
export const FIXTURE_ENTRYPOINT = {
fn: useRelayData,
params: [{ query: "", idx: 0 }],
sequentialRenders: [
{ query: "", idx: 0 },
{ query: "", idx: 0 },
{ query: "", idx: 1 },
],
};
```
### Eval output
(kind: ok) "1"
"1"
"2"

View File

@@ -0,0 +1,21 @@
import {useFragment} from 'shared-runtime';
/**
* React compiler should infer that the returned value is a primitive and avoid
* memoizing it.
*/
function useRelayData({query, idx}) {
'use memo';
const data = useFragment('', query);
return data.a[idx].toString();
}
export const FIXTURE_ENTRYPOINT = {
fn: useRelayData,
params: [{query: '', idx: 0}],
sequentialRenders: [
{query: '', idx: 0},
{query: '', idx: 0},
{query: '', idx: 1},
],
};

View File

@@ -0,0 +1,104 @@
## Input
```javascript
import {useIdentity, ValidateMemoization} from 'shared-runtime';
/**
* TODO fixture for granular iterator semantics:
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
* is a mutable iterator.
* 2. Capture effect on elements within the iterator.
*/
function Validate({x, input}) {
'use no memo';
return (
<>
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
<ValidateMemoization
inputs={[input]}
output={x[1]}
onlyCheckCompiled={true}
/>
</>
);
}
function useFoo(input) {
'use memo';
/**
* TODO: We should be able to memoize {} separately from `x`.
*/
const x = Array.from([{}]);
useIdentity();
x.push([input]);
return <Validate x={x} input={input} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [1],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { useIdentity, ValidateMemoization } from "shared-runtime";
/**
* TODO fixture for granular iterator semantics:
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
* is a mutable iterator.
* 2. Capture effect on elements within the iterator.
*/
function Validate({ x, input }) {
"use no memo";
return (
<>
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
<ValidateMemoization
inputs={[input]}
output={x[1]}
onlyCheckCompiled={true}
/>
</>
);
}
function useFoo(input) {
"use memo";
const $ = _c(5);
const x = Array.from([{}]);
useIdentity();
let t0;
if ($[0] !== input) {
t0 = [input];
$[0] = input;
$[1] = t0;
} else {
t0 = $[1];
}
x.push(t0);
let t1;
if ($[2] !== input || $[3] !== x) {
t1 = <Validate x={x} input={input} />;
$[2] = input;
$[3] = x;
$[4] = t1;
} else {
t1 = $[4];
}
return t1;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [1],
};
```
### Eval output
(kind: ok) <div>{"inputs":[],"output":{}}</div><div>{"inputs":[1],"output":[1]}</div>

View File

@@ -0,0 +1,36 @@
import {useIdentity, ValidateMemoization} from 'shared-runtime';
/**
* TODO fixture for granular iterator semantics:
* 1. ConditionallyMutate the iterator itself, depending on whether the iterator
* is a mutable iterator.
* 2. Capture effect on elements within the iterator.
*/
function Validate({x, input}) {
'use no memo';
return (
<>
<ValidateMemoization inputs={[]} output={x[0]} onlyCheckCompiled={true} />
<ValidateMemoization
inputs={[input]}
output={x[1]}
onlyCheckCompiled={true}
/>
</>
);
}
function useFoo(input) {
'use memo';
/**
* TODO: We should be able to memoize {} separately from `x`.
*/
const x = Array.from([{}]);
useIdentity();
x.push([input]);
return <Validate x={x} input={input} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [1],
};

View File

@@ -0,0 +1,130 @@
## Input
```javascript
import {useIdentity, ValidateMemoization} from 'shared-runtime';
/**
* Fixture to assert that we can infer the type and effects of an array created
* with `Array.from`.
*/
function Validate({x, val1, val2}) {
'use no memo';
return (
<>
<ValidateMemoization
inputs={[val1]}
output={x[0]}
onlyCheckCompiled={true}
/>
<ValidateMemoization
inputs={[val2]}
output={x[1]}
onlyCheckCompiled={true}
/>
</>
);
}
function useFoo({val1, val2}) {
'use memo';
const x = Array.from([]);
useIdentity();
x.push([val1]);
x.push([val2]);
return <Validate x={x} val1={val1} val2={val2} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{val1: 1, val2: 2}],
params: [
{val1: 1, val2: 2},
{val1: 1, val2: 2},
{val1: 1, val2: 3},
{val1: 4, val2: 2},
],
};
```
## Code
```javascript
import { c as _c } from "react/compiler-runtime";
import { useIdentity, ValidateMemoization } from "shared-runtime";
/**
* Fixture to assert that we can infer the type and effects of an array created
* with `Array.from`.
*/
function Validate({ x, val1, val2 }) {
"use no memo";
return (
<>
<ValidateMemoization
inputs={[val1]}
output={x[0]}
onlyCheckCompiled={true}
/>
<ValidateMemoization
inputs={[val2]}
output={x[1]}
onlyCheckCompiled={true}
/>
</>
);
}
function useFoo(t0) {
"use memo";
const $ = _c(8);
const { val1, val2 } = t0;
const x = Array.from([]);
useIdentity();
let t1;
if ($[0] !== val1) {
t1 = [val1];
$[0] = val1;
$[1] = t1;
} else {
t1 = $[1];
}
x.push(t1);
let t2;
if ($[2] !== val2) {
t2 = [val2];
$[2] = val2;
$[3] = t2;
} else {
t2 = $[3];
}
x.push(t2);
let t3;
if ($[4] !== val1 || $[5] !== val2 || $[6] !== x) {
t3 = <Validate x={x} val1={val1} val2={val2} />;
$[4] = val1;
$[5] = val2;
$[6] = x;
$[7] = t3;
} else {
t3 = $[7];
}
return t3;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{ val1: 1, val2: 2 }],
params: [
{ val1: 1, val2: 2 },
{ val1: 1, val2: 2 },
{ val1: 1, val2: 3 },
{ val1: 4, val2: 2 },
],
};
```
### Eval output
(kind: ok) <div>{"inputs":[1],"output":[1]}</div><div>{"inputs":[2],"output":[2]}</div>

View File

@@ -0,0 +1,42 @@
import {useIdentity, ValidateMemoization} from 'shared-runtime';
/**
* Fixture to assert that we can infer the type and effects of an array created
* with `Array.from`.
*/
function Validate({x, val1, val2}) {
'use no memo';
return (
<>
<ValidateMemoization
inputs={[val1]}
output={x[0]}
onlyCheckCompiled={true}
/>
<ValidateMemoization
inputs={[val2]}
output={x[1]}
onlyCheckCompiled={true}
/>
</>
);
}
function useFoo({val1, val2}) {
'use memo';
const x = Array.from([]);
useIdentity();
x.push([val1]);
x.push([val2]);
return <Validate x={x} val1={val1} val2={val2} />;
}
export const FIXTURE_ENTRYPOINT = {
fn: useFoo,
params: [{val1: 1, val2: 2}],
params: [
{val1: 1, val2: 2},
{val1: 1, val2: 2},
{val1: 1, val2: 3},
{val1: 4, val2: 2},
],
};

View File

@@ -27,7 +27,6 @@ describe('parseConfigPragmaForTests()', () => {
panicThreshold: 'all_errors',
environment: {
...defaultOptions.environment,
enableEmitHookGuards: null,
enableUseTypeAnnotations: true,
validateNoSetStateInPassiveEffects: true,
validateNoSetStateInRender: false,

View File

@@ -22,6 +22,8 @@ export {
findDirectiveEnablingMemoization,
findDirectiveDisablingMemoization,
type CompilerPipelineValue,
type Logger,
type LoggerEvent,
type PluginOptions,
} from './Entrypoint';
export {

View File

@@ -5,8 +5,6 @@
"moduleResolution": "Bundler",
"rootDir": "src",
"outDir": "dist",
// https://github.com/microsoft/TypeScript/issues/30925
"tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
"jsx": "react-jsxdev",
// weaken strictness from preset
"importsNotUsedAsValues": "remove",
@@ -16,8 +14,8 @@
"target": "ES2015",
// ideally turn off only during dev, or on a per-file basis
"noUnusedLocals": false,
"composite": true,
"removeComments": true
"removeComments": true,
"declaration": true,
},
"exclude": [
"node_modules",

View File

@@ -0,0 +1,28 @@
import {defineConfig} from 'tsup';
export default defineConfig({
entry: ['./src/index.ts'],
outDir: './dist',
external: ['@babel/types'],
splitting: false,
sourcemap: false,
dts: false,
bundle: true,
format: 'cjs',
platform: 'node',
target: 'es2015',
banner: {
js: `/**
* 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
*/`,
},
});

View File

@@ -4,9 +4,9 @@
"description": "ESLint plugin to display errors found by the React compiler.",
"main": "dist/index.js",
"scripts": {
"build": "rimraf dist && scripts/build.js",
"test": "tsc && jest",
"watch": "scripts/build.js --watch"
"build": "rimraf dist && tsup",
"test": "jest",
"watch": "yarn build --watch"
},
"files": [
"dist"
@@ -22,7 +22,7 @@
"devDependencies": {
"@babel/preset-env": "^7.22.4",
"@babel/preset-typescript": "^7.18.6",
"@babel/types": "^7.19.0",
"@babel/types": "^7.26.0",
"@types/eslint": "^8.56.12",
"@types/node": "^20.2.5",
"babel-jest": "^29.0.3",

View File

@@ -1,67 +0,0 @@
#!/usr/bin/env node
/**
* 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.
*/
const esbuild = require('esbuild');
const yargs = require('yargs');
const path = require('path');
const argv = yargs(process.argv.slice(2))
.options('w', {
alias: 'watch',
default: false,
type: 'boolean',
})
.parse();
const config = {
entryPoints: [path.join(__dirname, '../src/index.ts')],
outfile: path.join(__dirname, '../dist/index.js'),
bundle: true,
external: [
'@babel/core',
'@babel/plugin-proposal-private-methods',
'hermes-parser',
'zod',
'zod-validation-error',
],
format: 'cjs',
platform: 'node',
banner: {
js: `/**
* 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
*/
"use no memo";`,
},
};
async function main() {
if (argv.w) {
const ctx = await esbuild.context(config);
await ctx.watch();
console.log('watching for changes...');
} else {
await esbuild.build({
sourcemap: true,
minify: false,
...config,
});
}
}
main();

View File

@@ -7,22 +7,27 @@
import ReactCompilerRule from './rules/ReactCompilerRule';
module.exports = {
rules: {
'react-compiler': ReactCompilerRule,
},
configs: {
recommended: {
plugins: {
'react-compiler': {
rules: {
'react-compiler': ReactCompilerRule,
},
const meta = {
name: 'eslint-plugin-react-compiler',
};
const rules = {
'react-compiler': ReactCompilerRule,
};
const configs = {
recommended: {
plugins: {
'react-compiler': {
rules: {
'react-compiler': ReactCompilerRule,
},
},
rules: {
'react-compiler/react-compiler': 'error',
},
},
rules: {
'react-compiler/react-compiler': 'error',
},
},
};
export {configs, rules, meta};

View File

@@ -6,7 +6,7 @@
*/
// v0.17.1
declare module "hermes-eslint" {
declare module 'hermes-eslint' {
// https://fburl.com/2vikhmaa
type ParseForESLintOptions = {
/**
@@ -37,7 +37,7 @@ declare module "hermes-eslint" {
/**
* The source type of the script.
*/
sourceType: "script" | "module";
sourceType: 'script' | 'module';
/**
* Ignore <fbt /> JSX elements when adding references to the module-level `React` variable.

View File

@@ -6,14 +6,14 @@
*/
// v0.17.1
declare module "hermes-parser" {
declare module 'hermes-parser' {
type HermesParserOptions = {
allowReturnOutsideFunction?: boolean;
babel?: boolean;
flow?: "all" | "detect";
flow?: 'all' | 'detect';
enableExperimentalComponentSyntax?: boolean;
sourceFilename?: string;
sourceType?: "module" | "script" | "unambiguous";
sourceType?: 'module' | 'script' | 'unambiguous';
tokens?: boolean;
};
export function parse(code: string, options: Partial<HermesParserOptions>);

View File

@@ -6,9 +6,6 @@
"rootDir": "../",
"noEmit": true,
"jsx": "react-jsxdev",
"paths": {
"*": ["./src/types/*"]
},
// weaken strictness from preset
"importsNotUsedAsValues": "remove",

Some files were not shown because too many files have changed in this diff Show More