Commit Graph

1417 Commits

Author SHA1 Message Date
Sathya Gunasekaran 2efd85f145 Convert CompilationModeScham to zod type 2023-11-14 11:46:26 +00:00
Sathya Gunasekaran 084e4325b9 Convert PanicThresholdOptions to zod type 2023-11-14 11:46:23 +00:00
Sathya Gunasekaran 0821a57fa8 [playground] Capture Babel parsing errors
Before: 

<img width="1416" alt="Screenshot 2023-11-14 at 9 09 53 AM" 
src="https://github.com/facebook/react-forget/assets/565765/f53daf34-080a-4804-9a61-77c141c05d21"> 

After: 

<img width="1444" alt="Screenshot 2023-11-14 at 9 09 45 AM" 
src="https://github.com/facebook/react-forget/assets/565765/8861c266-9a49-4ff7-99cd-7240ca1750b1">
2023-11-14 18:24:38 +00:00
Sathya Gunasekaran 07d6c6d8aa [playground] Show error when compiling unsupported functions
Before: 

<img width="1117" alt="Screenshot 2023-11-14 at 9 11 28 AM" 
src="https://github.com/facebook/react-forget/assets/565765/d1ec2b5f-1bc5-4d29-9811-effcd39581e4"> 

After: 

<img width="1115" alt="Screenshot 2023-11-14 at 9 11 18 AM" 
src="https://github.com/facebook/react-forget/assets/565765/9a41889c-cf7b-4f31-8b6e-e26bfb204883">
2023-11-14 09:10:31 +00:00
Sathya Gunasekaran 0794aacdbf Turn off validateNoSetStateInRender in babel-plugin
There's false positives that we found in the Eslint plugin
2023-11-14 16:59:10 +00:00
Sathya Gunasekaran 1641f94a86 [eslint] Turn off validations
We're seeing false positives
2023-11-14 16:59:09 +00:00
Sathya Gunasekaran 3da32312e7 [globals] type useEffect return value as primitive
useEffect returns undefined
2023-11-13 10:51:08 +00:00
Lauren Tan 480c11bdb1 [hoisting] Make hoisting related errors consolidatable
Noticed from our paste that we weren't correctly rolling up hoisting related 
errors due to specific information being in the error title, so this PR moves 
them into description instead.
2023-11-13 16:54:54 -05:00
Joe Savona 800b874ed1 fix main
Forgot to update snapshots when addressing PR feedback.
2023-11-13 13:14:27 -08:00
Joe Savona e6c5c9a005 Improve NoSetStateInRender function expression check
Updates the approach used in ValidateNoSetStateInRender to detect function 
expressions called during render. We now do the following: 

* Track function expression which are known to unconditionally call setState 
themselves- if these functions get called, that’s equivalent to calling 
setState. We call the validation recursively to compute this. 

* Track LoadLocal/StoreLocal indirections for such function expressions. 

* Check CallExpressions where the callee is either a known SetState (via type 
info) _or_ (new) where the callee is in the set of known-to-setState function 
expressions. 

The Set is shared throughout the analysis, so we can even find multiple levels 
of indirection (see new test case).
2023-11-13 11:28:16 -08:00
Joe Savona dcbdf06491 Extra test case related to memoization "within" freeze
I found an interesting edge case in the previous diff with mutation of a value 
that appears in the expression of an object key: 

```javascript 

const key = {} 

const object = { 

[mutateAndReturnOtherValue(key)]: 42, 

}; 

mutate(key); 

``` 

We analyze and represent this correctly all the way through to codegen, but then 
we hit the bug that @mofeiZ has noticed before: the temporary for `t = 
mutateAndReturnOtherValue(key)` isn't emitted immediately (bc its a temporary). 
It gets emitted inside the memo block for `object`, which is incorrect. 

I tried to reproduce that here with JSX and it works as expected. It's an 
interesting case though so let's land this to ensure we don't regress.
2023-11-13 11:03:00 -08:00
Joe Savona 8d41529600 Support computed object keys 2023-11-13 09:55:52 -08:00
Mofei Zhang f47685c602 [be] Flag and test for unexpected exceptions during compilations 2023-11-12 14:56:10 -05:00
Mofei Zhang 7db2388fff [be] tsconfig: useUnknownInCatchVariables 2023-11-12 14:44:15 -05:00
Joe Savona 3d2a05490f Update eslint plugin to enable more safe validations 2023-11-10 17:08:26 -08:00
Joe Savona fc85f24865 Separate flag for ref access violation within function expressions
Adds a separate compiler flag for enabling the incomplete validation of ref 
access within function expressions. Unlike the previous PR for 
set-state-in-render validation, ref access in render can be okay in some 
circumstances so i'm leaving this off by default. The point of splitting this up 
is that our linting will be able to enable the rule without risk of false 
positives.
2023-11-10 17:07:21 -08:00
Joe Savona 6e038f9699 Partially enable validateNoSetStateInRender
The approach i initially took to validating function expressions was to try to 
extend the mutable range if they are called during render, and then use the 
mutable range of a function to determine if it's called during render later. 
However there are cases where the range can be extended for other reasons, as 
@poteto discovered, so we can't rely on the range extension. We've had several 
of our validations completely off as a result of this. 

In this PR i'm re-enabling @poteto's ValidateNoSetStateInRender pass by default, 
but making the function expression checking use a separate compiler flag. This 
means we'll have some false negatives, but should guarantee that we avoid false 
positives. This means we can definitely catch things like: 

``` 

const [state, setState] = useState(false); 

setState(true); 

``` 

Which we would have allowed by default before.
2023-11-10 16:52:29 -08:00
Mofei Zhang c08b7be34e [be] Add comments for LoggerEvent type 2023-11-10 17:09:31 -05:00
Mofei Zhang 9965db70bd Revert "[babel] Remove unused PipelineError"
This reverts commit 10d129a8406e9d226abdb6943bf8512e34ce91db 

--- 

Reverts #2311 due to undocumented assumptions being broken. I also added some 
comments to `LoggerEvents` to explain each event type. 

In `Program.ts`, we have something like the following code. `compile` could 
produce any number of errors (not just expected errors / instances of 
`CompilerError`). As an example, we sometimes error in `Codegen` due to babel 
version incompatibilities (`Error: ObjectMethod: Too many arguments passed. 
Received 7 but can receive no more than 5`). 

```js 

try { 

// any error could be thrown here 

compile(input); 

} catch (e) { 

// unknown type for e 

handleError(e, ...); 

} 

```
2023-11-10 17:09:29 -05:00
Sathya Gunasekaran bd3661020e Add test for bailouts skipping compilation 2023-11-09 12:00:37 +00:00
Sathya Gunasekaran 69eb9ccccc [snap] Add option to set panicThreshold 2023-11-09 12:00:34 +00:00
Joe Savona f92a058ca5 Codegen comments to explain output 2023-11-10 11:45:29 -08:00
Joe Savona 956c1ee7e2 Repro for bug with incorrectly using context variables when name overlaps 2023-11-01 17:42:14 -07:00
Joe Savona ab0f698585 More tests for fbt whitespace handling
I experimented with more variations but prettier collapses most of them: any run 
of consecutive whitespace within a jsxtext node will get collapsed into a single 
space, for example. So the main difference in practice is whether a jsxtext node 
(preceding a value) has a trailing space/newline or not: 

``` 

Text <fbt:param /> Text 

// vs 

Text<fbt:param />Text 

``` 

which we now have tests for.
2023-11-10 11:21:10 -08:00
Joe Savona 127b5df7ca [be] Group fbt fixtures in directory 2023-11-10 11:21:07 -08:00
Joe Savona 6f2fe1e7e9 Fix FBT whitespace handling (again (again))
Nice find, @mofeiZ! I really tried to thoroughly test all the examples I could 
think of for FBT whitespace but i missed the newline case. Initially Mofei found 
[this code potentially related to whitespace 
handling](https://github.com/facebook/fbt/blob/main/packages/babel-plugin-fbt/src/fbt-nodes/FbtImplicitParamNode.js#L230-L233) 
but Babel never seems to produce consecutive JsxText nodes — this looks like 
maybe a leftover from older babel versions. 

I noticed that code wasn't actually trimming the whitspace but clearly it was 
happening somewhere, so i grepped for 'trim' and found that [this 
code](https://github.com/facebook/fbt/blob/0b4e0d13c30bffd0daa2a75715d606e3587b4e40/packages/babel-plugin-fbt/src/babel-processors/JSXFbtProcessor.js#L143) 
calls a 
[normalizeSpaces](https://github.com/facebook/fbt/blob/0b4e0d13c30bffd0daa2a75715d606e3587b4e40/packages/babel-plugin-fbt/src/FbtUtil.js#L86C10-L86C45) 
helper. Updating our logic to handle whitespace similarly just for children of 
fbt nodes produces the expected result.
2023-11-10 10:21:10 -08:00
Lauren Tan 82ed13b8b4 [eslint] Don't inline everything
Turns out this will cause an OOM in node.js when running eslint as part of the 
IDE 

``` Before: 16M   packages/eslint-plugin-react-forget/dist/index.js After:  2.2M 
 packages/eslint-plugin-react-forget/dist/index.js ```
2023-11-10 13:49:30 -05:00
Joe Savona 2927792dca Extra tests for #2339 2023-11-10 09:25:40 -08:00
Joe Savona 4742d27f9e [be] Clarify naming in scope merging pass
Anytime we have a nested `.scope` in code my brain hurts. For example 
`scope.scope.dependencies`. This PR updates the scope merging pass to use the 
name `scopeBlock` for a ReactiveScopeBlock and `scope` only for ReactiveScope 
values, to make things a bit more clear.
2023-11-09 16:33:41 -08:00
Joe Savona 691cad6b51 Optimization for scope merging when no deps
Addresses T168684688 (#2242). MergeReactiveScopesThatInvalidateTogether does not 
merge scopes if their output is not guaranteed to change when their inputs do. 
So for example a case such as `{session_id: bar(props.bar)}` will not merge the 
scopes for `t0 = bar(props.bar)` and `t1 = {session_id: t0}`, because t0 isn't 
guaranteed to change when `props.bar` does, and we want to avoid recreating the 
t1 object unless it semantically changes. 

But there's a special case: if a scope has no dependencies, then we'll never 
execute it again anyway. So it doesn't matter what kind of value it produces and 
it's safe to merge with subsequent scopes: 

```javascript 

return {session_id: bar()} 

``` 

Without the reactive input, `bar()` will always return the same value since 
we'll only ever call it once anyway. So it's safe to then merge with the scope 
for the outer object literal.
2023-11-09 16:21:00 -08:00
Sathya Gunasekaran e35df45eaf Test component name access in gated setup
Jesse flagged this as a potential bug internally but this looks correct to me. 

Adding a test case so that we don't regress in the future.
2023-11-09 10:30:54 +00:00
Sathya Gunasekaran cdf39e7956 [sprout] Add ReactForgetFeatureFlag 2023-11-09 10:30:52 +00:00
Mofei Zhang 6c327b0f3e [repro] Repro for fbt preserve whitespace bug
Current sprout output (if you remove the line in `SproutTodoFilter`): 

``` 

Failures: 

FAIL: bug-fbt-preserve-whitespace 

Difference in forget and non-forget results. 

Expected result: { 

"kind": "ok", 

"value": "Before text hello world", 

"logs": [] 

} 

Found: { 

"kind": "ok", 

"value": "Before texthello world", 

"logs": [] 

} 

``` 

`fbt` transforms run before jsx ones, so our lowering should also account for 
[fbt's whitespace 
rules](https://github.com/facebook/fbt/blob/main/packages/babel-plugin-fbt/src/fbt-nodes/FbtImplicitParamNode.js#L230-L233) 
in `BuildHIR:trimJsxText`.
2023-11-09 18:55:06 -05:00
Mofei Zhang 59ddf537ed [tests][fixtures] Enable sprout on basic existing fbt tests
--- 

Output: 

``` 

$ yarn sprout:build && yarn sprout --verbose 

... 

PASS  fbt-call-complex-param-value 

ok <div>Hello, Sathya!</div> 

PASS  fbt-call 

ok <div>2 items</div> 

PASS  fbt-template-string-same-scope 

ok <div>{"children":"for 3 experiences"}</div> 

... 

```
2023-11-09 18:55:05 -05:00
Mofei Zhang 372696c541 [sprout] Add support for fbt
Fbt + typescript [seems](https://github.com/facebook/fbt/issues/49) [to 
be](https://github.com/facebook/sfbt/issues/72) a non-blessed workflow. We do 
want to allow for both flow and typescript tests, so I followed some 
instructions [from a 
guide](https://dev.to/retyui/how-to-add-support-typescript-for-fbt-an-internationalization-framework-3lo0) 
to add support. 

- fbt tags desugar to.. "fbt" strings. By default, typescript removes unused 
imports at parse step (and on autoformat steps). We pass special 
babel-typescript configs and change vscode settings to mitigate this. 

- I tried adding `fbt` to the global scope, but the fbt transform asserts that 
`fbt` is actually imported in the source program. 

- Other hacks are available, like saying we'll only allow for fbt in flow files, 
or always patching the source code to have an "fbt" import. This seemed the most 
reasonable and easiest to debug / follow when writing tests
2023-11-09 18:55:05 -05:00
Mofei Zhang b25c14feb1 [tests][be] Clean up fixture selection logic
--- 

Refactor selection logic to be easier to read; add support for .jsx test files 
(feels a bit weird adding a `.jsx` fixture and not seeing it get run)
2023-11-09 16:50:00 -05:00
Lauren Tan 2726484823 Add license to rolledup output 2023-11-09 13:00:13 -05:00
Lauren Tan a6e492d8d0 [feedback] Add script to build packages for testapp
In order to make changes to the testapp's dependencies, we need to update the 
lockfile which means modules need to actually exist. This adds a new script to 
just run a build of the packages we sync so that module resolution in the 
testapp will work
2023-11-09 11:31:33 -05:00
Sathya Gunasekaran f13594280b [ez] Use BabelFn type 2023-11-09 08:38:00 +00:00
Lauren Tan bb92520ba5 Some existing InvalidConfig errors should be invariants
Now that we have validation of the compiler config, these old errors weren't 
categorized correctly. Readjusted them to be invariants instead.
2023-11-08 14:10:18 -05:00
Lauren Tan 973ec414bd [eslint] Try inlining everything in build 2023-11-08 15:19:07 -05:00
Sathya Gunasekaran 7aca04a0d6 [babel] Refactor handleError to pass the error first
Pass the most important and required argument as the first parameter.
2023-11-08 16:09:19 +00:00
Sathya Gunasekaran 4e7d437880 [babel] Remove unused PipelineError
Most of the use cases are already handled with ErrorSeverity.InvalidConfig
2023-11-08 16:09:18 +00:00
Sathya Gunasekaran 0beeb1e7ad Remove unncessary nullcheck 2023-11-08 16:09:18 +00:00
Sathya Gunasekaran 521f056875 Always clone DEFAULT_HOOKS
Reusing DEFAULT_HOOKS instance is a bit scary in case we mutate it by mistake 
and this gets reflected across all compiles. 

This isn't a concern now as we can't change the config during compilation. But 
this PR keeps us safe in case we change this behavior in the future. 

The tradeoff is a bit of perf which I think is the right tradeoff here.
2023-11-08 16:09:17 +00:00
Sathya Gunasekaran ec089d5454 [test] Add test to make sure stringy enums are parsed correct
Meta internal config is going to be stringy, so let's add tests.
2023-11-08 16:09:16 +00:00
Sathya Gunasekaran 6d2fce8eb5 Make CustomHooks optional and add default value
Don't propogate nullability into the plugin.
2023-11-08 16:09:16 +00:00
Sathya Gunasekaran 8b12f179d3 Add tests to make sure our config validation error message doesn't regress 2023-11-08 16:09:15 +00:00
Sathya Gunasekaran 3f7b9e23e3 Don't allow null to be passed to validateEnvironmentConfig
zod will throw an error if we pass null, so let's not do this. 

Adding a temporary workaround until we start validating PluginOptions.
2023-11-08 16:09:14 +00:00
Sathya Gunasekaran 42497b60f5 [error] Prefix side-effecting function names with throw
I did a double take when I thought we didn't handle returning the 

error when reading the code and when I edited the code, typescript told 

me that there's no need to return as creating the error will throw. 

This PR makes it clear from the name of the function that we will throw.
2023-11-08 16:09:13 +00:00