closes#6227
I noticed that the implementation of `collapse-variable-declarations`
seems incomplete and appears quite simple. Therefore, I would like to
quickly add all the test cases to work on this.
Previously, I saw that `DonIsaac` had also submitted a related PR, but
he might have been too busy to respond for a long time. I want to
apologize for closing his PR.
This will fold expressions like `new Object()` to `{}`, and `new Array()` to `[]`. Based on the closure compiler tests: b7e380b632/test/com/google/javascript/jscomp/PeepholeSubstituteAlternateSyntaxTest.java (L78).
This is outside my usual area, so feedback is welcome.
NOTE: this was previously a full stack of PRs, but Graphite decided to stop working completely for some reason and only gave me this error when I submitted a PR:
```
ERROR: Failed to submit PR for 10-02-feat_minifier_fold_single_arg_new_array_expressions:
{}
```
so I decided to just completely remake this stack and submit as 1 PR.
These are minor changes, and recently I’ve been learning and trying to
implement some features of `oxc_minifier`, which feels a bit complex.
By the way, I’m wondering whether we should gradually add test cases
during the feature implementation process or just copy all the
corresponding tests directly? Perhaps we could implement something like
`rulegen` similar to `linter`?
```rs
test("x = ~2147483658.0", "x = 2147483637");
test("x = ~-2147483658", "x = -2147483639");
```
Used `wrapping_neg`, and maybe it is a great solution for #6161.
resolves#6201.
It is uncertain whether this applies to other situations, so let us eliminate it in negation first, and after I have conducted a comprehensive investigation of the Closure Compiler, we can make a definitive decision.
I expect small performance regression.
But managed to improve the following case from react.developmement.js
```
oxc main ❯ diff before.js after.js
670c670
< if (!(dispatcher !== null)) throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.");
---
> if (dispatcher === null) throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.");
```
After studying google closure compiler, I'm leaning towards a multi-ast-pass infrastructure for the minifier.
This is one of the few places where we are going to trade maintainability over performance, given the goal of the minifier is compression size not performance.
All of the terminologies and separation of concerns are aligned with google closure compiler.
Infrastructure of `terser` and `esbuild` are not suitable for us to study nor pursuit. Their code are so tightly coupled - I failed to comprehend any of them every time I try to walk through a piece of optmization. Google closure compiler despite being written in Java, it's actually the most readable minifier out there.
To improve performance between ast passes, I envision a change detection system over a portion of the code.
The benchmark will demonstrate the performance regression of running 5 ast passes instead of 2.
To complete this PR, I need to figure out "fix-point" and order of these ast passes.
We have a strange workaround for `visit_function` where we pass in `ScopeFlags`, to support creating the scope inside `Function`, but setting different flags for `MethodDefinition`s.
Previously `visit_function` took `Option<ScopeFlags>` and then did `flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function` to it. Personally, I found this confusing. When I was looking at `MethodDefinition`, I was wondering "It's a function, why doesn't it set Function flag too?"
This changes makes it more explicit and clear what `ScopeFlags` everything has.