Large re-architecting of class properties transform. Split transform into 3 phases:
1. Transform instance properties when entering class.
2. Transform private fields during traversal of class body.
3. Transform static properties and static blocks when exiting class.
This ensures that code which has to be moved outside of the class (static property initializers, static blocks, computed keys) can get transformed by other transforms before they're moved out.
Also fixes a problem where we previously registered private properties too early - on entering the class, rather than the class *body*, so private fields in `extends` clause of a nested class were misinterpretted.
Record "block" scope ID along with "hoist" scope ID in `Traverse`.
"Block" scope is the scope where a `let` statement would be inserted above current position in AST.
Block scope and current scope differ from each other inside classes. For example, if want to create a `let` temp var for `foo()` or `bar()` in example below, should use block scope not current scope. Current scope is the class itself, but the `let` statement will be inserted *outside* the class.
```js
class C {
[foo()]: bar();
}
```
All transforms which create `let` bindings should use block scope not current scope. We should add `VarDeclarationsStore::insert_let` method which uses block scope, to accompany `insert_var` (which uses hoist scope).
This is implemented in a rather hacky way, and we should improve it later. Notably, we're not considering `for` statements as block scopes because we currently have no way to insert `let` statements into them if they don't have a body block.
The purpose of `AstBuilder::move_*` methods is to create dummy nodes which will later be replaced again. Give the dummy nodes empty spans as it's faster, and no point in them having a real span.
When inserting instance property initializers into class constructor, need to search for and transform `super()`. Exit that visit earlier in some cases, for better performance and smaller output.
Rename these methods. `is_via_*` is confusing as hell. `is_parent_of_*` is more descriptive.
`Ancestor::is_parent_of_statement` tells you if *previous* `Ancestor` is a `Statement`.
#8019 changed scope bindings from an ordered `IndexMap` to an unordered `FxHashMap`.
`ScopeTree::rename_binding` no longer needs to preserve order, so can remove the old binding before adding the new one. This makes it less likely that the hash map will need to reallocate.
Also remove comments about preserving ordering of bindings, which are now outdated.
Small optimization. When generating hash of hooks key, build the hash string directly in arena, avoiding an intermediate heap-allocated `String`, by using `base64` crate's `encode_slice` method which writes directly into a slice.
`base64` crate is rather inefficient - there are various optimizations that could be made. But not worth getting into that, as this is only place we use `base64` crate in a performance-sensitive context.
Bumpalo has a method `String::from_utf8_unchecked` to covert a `Vec<u8>` to a `String`. But we can't use it because we use Bumpalo's `String` as our arena string type, but allocator_api2's `Vec` as our arena vec.
Provide the same functionality, that works around this incompatibility. Also use the faster `simdutf8` for checking that `Vec` contains a valid UTF-8 string.
Follow-on after #8013. Reserve sufficient capacity in `String` used to store hook key, before pushing to it.
Also refactor so code for constructing key is only included once.
`IndexMap` was needed for the insertion order requirement in mangler.
Bindings (symbol ids) are monotonically increasing by binding
positions, which means we can get insertion order by sorting the symbol ids in
mangler.
Previous attempt: https://github.com/oxc-project/oxc/pull/4228
Follow-on after #7997.
Generate "base name" for temp var using `temp_var_name_base` and then create the 2 temp bindings from it.
This is a bit more efficient than creating 2nd temp binding from name of the first temp binding, because the first binding's name has `_` added to start, and may have digits on the end, which have to be trimmed off again. Whereas the "base name" is ready to go.
Incidentally, changing the timing of when temp bindings are created also aligns output with Babel.
Amend test added in #7991 to test transform of `super[prop] = value` where `prop` is not bound.
We should ideally have the `_unbound` temp vars *inside* the arrow function rather than outside, as Babel does, but that's not possible with our double-visitor scheme at present, and I think current output will operate correctly anyway.
Probably these temp vars could be hoisted even higher up - to very top level of the file, even if the class and `super[prop]` were deeply nested in many functions - and it'd still be correct. That'd be good for transformer performance as less `var` statements to insert, and also slightly smaller output size - less `var`s in code. But I don't know if that would be worse for runtime performance, as it makes the arrow function more impure. 🤔
Alternative of #7956 and #7959. Unlike the previous method, adapting duplicating the same logic rather than making the same logic transform function to be generic
I just found that we don't need to transform `TaggedTemplateExpression` because its `tag` can be transformed by `transform_static_member_expression` and `transform_computed_member_expression`
We have reset current_reference_flags after resolving reference flags in https://github.com/oxc-project/oxc/pull/7923, so that we don't need to set it to empty in another place.