We don't transform private methods yet, but in class properties transform, still need to record private methods that classes have, so can correctly resolve private fields.
```js
class Outer {
#foo = 123;
method() {
class Inner {
#foo() {}
// Refers to `Inner`'s `#foo` method, not `Outer`'s `#foo` property
prop = this.#foo;
}
}
}
```
This PR implements folding `foo === undefined || foo === null` into `foo
== null`.
I checked the minified output diff this time, so hoping that there isn't
a bug.
Add failing test for nullish coalescing operator. The output is correct, but temp var is created in wrong scope.
My guess is that it needs to use `current_hoist_scope_id`, not `current_scope_id`.
This test from class properties also shows the same problem: ac097e9160/tasks/transform_conformance/snapshots/oxc.snap.md (L20-L35)
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.
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.
`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`
Don't transform `super` in static property initializers if it's nested in another method, so is a *different* `super`.
```js
class C {
static prop = () => {
const object = {
method() {
// `super` here refers to prototype of `object`, not class `C`
return super.foo;
}
};
};
}
```
Pure refactor. Use `bench_function` instead of `bench_with_input` and
just borrow data from outside closure. This shortens the code and (I
think) makes it easier to read.
close: #7900
After #4283 changed, we don't need to inherit `ScopeFlags` from the `constructor`, `set`, `get` anymore, I think this is a logic of forgetting to remove
For this case, we set `current_reference_flags` to `ReferenceFlags::Type` for `TSInterfaceHeritage`, but never unset it, which causes resolving `fowardRef` identifier reuse `current_reference_flags` of `TSInterfaceHeritage`.
```ts
import { forwardRef } from "react";
export interface MenuTriggerProps extends Object {}
export const MenuTrigger = forwardRef();
```
In this PR, reset the `current_reference_flags` when resolved, so that we don't need to reset it in individual visit functions. This is a reasonable change because the `current_reference_flags` only applies to the next encountered identifier.
Adds `top_level` option which is similar to [terser's `toplevel`
option](https://terser.org/docs/cli-usage/#cli-mangle-options).
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Add a fast path for inserting instance property initializers into constructor, when no existing constructor or constructor has no bindings. This should be reasonably common.
The `Scope flags mismatch` errors are due to #7900.
#7872 implements renaming symbols in constructor which shadow references in instance property initializers. But we don't need to rename where the reference in initializer references a symbol which is bound within the initializer itself.
Input:
```js
class C {
double = n => n * 2;
constructor(n) {
console.log(n);
}
}
```
Output:
```js
class C {
constructor(n) { // <-- not renamed
this.double = n => n * 2; // <-- moved into constructor
console.log(n); // <-- not renamed
}
}
```
This produces better output, and avoids a traversal of constructor's AST renaming symbols.
Instance property initializers are moved into constructor. If symbols they reference are shadowed within constructor, rename those symbols.
Input:
```js
class C {
prop = foo();
constructor(foo) {
console.log(foo);
}
}
```
Output:
```js
class C {
constructor(_foo) { // <-- renamed
this.prop = foo(); // <-- moved into constructor
console.log(_foo); // <-- renamed
}
}
```