Commit graph

543 commits

Author SHA1 Message Date
Dunqing
0592a8b43f feat(transformer/class-properties): transform private in expression (#8202)
This PR support transforms `#prop in object` in class-properties to cover https://www.npmjs.com/package/@babel/plugin-transform-private-property-in-object  plugin does
2024-12-31 12:30:58 +00:00
Dunqing
80c16526fb chore(transformer): enable Babel's private-property-in-property plugin tests (#8201) 2024-12-31 12:30:57 +00:00
Dunqing
3c77ed1af1 feat(transform-conformance): support enabling all class-related plugins when any of them are enabled in update_fixtures (#8200)
The `class-properties` plugin supports all class-related plugins, so we need to ensure that once any of them are enabled, we also enable all class-related plugins.
2024-12-31 12:30:57 +00:00
Dunqing
ad77ad5c12 feat(transformer/class-properties): transform static/instance accessor methods (#8132)
This PR supports transforming private `getter` or `setter` methods, and the output is a little different from Babel's output, For example:

Input:
```js
class Cls {
  #prop = 0;

  get #accessor() {
    return this.#prop;
  }
  set #accessor(v) {
    console.log(arguments);
    this.#prop = v;
  }

  constructor() {
    console.log(this.#accessor)
    [this.#accessor] = [1];
  }
}
```

[Babel's output](https://babeljs.io/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=MYGwhgzhAEDCIwN4ChrQMQAcBOB7T0AvNAAwDcyq0A5gKYAuGYwwtUu2AFAJTQpppsDAK7YAdtHoALAJYQAdFjyYKaAL5UIDJizYQOnAG69-A4LjH6QteSFzVOYbNWEBbWmPoRuqgdLmKOPhE0Ia-GlTmlvTYwsD0BiZUaFFWNnYO_grozKzs2NzJ0ADaWYq5ehwAuiHFAIxV4cgaQA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&evaluate=false&fileSize=false&timeTravel=false&sourceType=script&lineWrap=true&presets=&prettier=false&targets=&version=7.26.4&externalPlugins=%40babel%2Fplugin-transform-class-properties%407.25.9%2C%40babel%2Fplugin-transform-private-methods%407.25.9%2C%40babel%2Fplugin-external-helpers%407.25.9&assumptions=%7B%7D):
```js
var _prop = new WeakMap();
var _Cls_brand = new WeakSet();
class Cls {
  constructor() {
    babelHelpers.classPrivateMethodInitSpec(this, _Cls_brand);
    babelHelpers.classPrivateFieldInitSpec(this, _prop, 0);
    console.log(babelHelpers.classPrivateGetter(_Cls_brand, this, _get_accessor));
    [babelHelpers.classPrivateGetter(_Cls_brand, this, _get_accessor)] = [1];
  }
}
function _get_accessor(_this) {
  return babelHelpers.classPrivateFieldGet(_prop, _this);
}
function _set_accessor(_this2, v) {
  var _arguments = [].slice.call(arguments, 1);
  console.log(_arguments);
  babelHelpers.classPrivateFieldSet(_prop, _this2, v);
}
```

Oxc's output:
```js
var _prop = new WeakMap();
var _Cls_brand = new WeakSet();
class Cls {
        constructor() {
                babelHelpers.classPrivateMethodInitSpec(this, _Cls_brand);
                babelHelpers.classPrivateFieldInitSpec(this, _prop, 0);
                console.log(_get_accessor.call(babelHelpers.assertClassBrand(_Cls_brand, this)));
                [babelHelpers.toSetter(_set_accessor.bind(babelHelpers.assertClassBrand(_Cls_brand, this)), [])._] = [1];
        }
}
function _get_accessor() {
        return babelHelpers.classPrivateFieldGet2(_prop, this);
}
function _set_accessor(v) {
        console.log(arguments);
        babelHelpers.classPrivateFieldSet2(_prop, this, v);
}
```

### Main difference
```diff
// Babel
+ console.log(babelHelpers.classPrivateGetter(_Cls_brand, this, _get_accessor));
+ [babelHelpers.classPrivateGetter(_Cls_brand, this, _get_accessor)] = [1];

+ function _get_accessor(_this) {
+   return babelHelpers.classPrivateFieldGet(_prop, _this);
+ }

+ function _set_accessor(_this2, v) {
+   var _arguments = [].slice.call(arguments, 1);
+   console.log(_arguments);
+   babelHelpers.classPrivateFieldSet(_prop, _this2, v);
+ }

// Oxc
-  console.log(_get_accessor.call(babelHelpers.assertClassBrand(_Cls_brand, this)));- -
-  [babelHelpers.toSetter(_set_accessor.bind(babelHelpers.assertClassBrand(_Cls_brand, this)), [])._] = [1];

- function _get_accessor() {
-   return babelHelpers.classPrivateFieldGet2(_prop, this);
- }

- function _set_accessor(v) {
-   console.log(arguments);
-   babelHelpers.classPrivateFieldSet2(_prop, this, v);
- }
```

From the main differences, we can see that Babel handles `getter` and `setter` methods using `classPrivateGetter` and `classPrivateSetter` helper functions, which causes all use `this` and `arguments` needs to rewrite to use a temp var instead in `getter` and `setter` methods. This is unnecessary and is not an efficient transformation for us.

Instead, I adapt binding a `this` instead of passing in `this`, this way we don't need to rewrite anything. We can't control the `helper` library for now, so I just transformed the AST to bind `this`, in the future, we can create a helper function to do the same thing.
2024-12-31 12:30:56 +00:00
Dunqing
e405f79577 feat(transformer/class-properties): transform static private method invoking (#8117) 2024-12-31 12:30:56 +00:00
Dunqing
3303e9986b feat(transformer/class-properties): insert statements after statement of class expression (#8116) 2024-12-31 12:30:55 +00:00
Dunqing
0cc71cf5e3 feat(transformer/class-properties): transform super expressions and identifiers that refers to class binding in private method (#8106)
All private methods will be moved out of class, so we need to transform all `super` expressions in private methods and transform identifiers that refer to class binding.
2024-12-31 12:30:55 +00:00
Dunqing
58ed83242a feat(transformer/class-properties): transform private field expression which invokes private method (#8102) 2024-12-31 12:30:53 +00:00
Dunqing
f14567a658 feat(transformer/class-properties): transform callee which invokes private method (#8100)
transform call expression's callee if it invokes a private method
2024-12-31 12:30:52 +00:00
Dunqing
13349ef1b8 feat(transformer/class-properties): transform private methods (#8099)
This PR support transforms private methods in a class, moving all of them to after the `class`
2024-12-31 12:30:52 +00:00
Dunqing
6af5870a7d chore(transformer): enable Babel's private-methods plugin tests (#8098)
part of #8052
2024-12-31 12:30:51 +00:00
Boshen
e632a7b158 feat(transformer): remove typescript symbols after transform (#8069)
part of #7460
2024-12-23 08:24:54 +00:00
overlookmotel
6b08c6e6c4 fix(transformer/class-properties): correctly resolve private fields pointing to private methods (#8042)
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;
    }
  }
}
```
2024-12-23 03:44:08 +00:00
camc314
274f117d4e fix(transformer/nullish-coalescing): use correct scope id for binding (#8053) 2024-12-21 07:08:29 +00:00
overlookmotel
3d83396f0b test(transformer/nullish-coalescing): failing test (#8051)
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)
2024-12-21 07:08:29 +00:00
overlookmotel
043252dcd1 fix(transformer/class-properties): replace this and class name in static blocks (#8035)
Transform `this`, class name, and `super` in static blocks.
2024-12-20 10:07:23 +00:00
overlookmotel
273795d471 fix(transformer/class-properties): run other transforms on static properties, static blocks, and computed keys (#7982)
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.
2024-12-20 10:07:23 +00:00
overlookmotel
897a1a8946 feat(transformer/class-properties): exit faster from super replacement visitor (#8028)
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.
2024-12-20 03:10:22 +00:00
overlookmotel
0a38eea95c refactor(transformer/class-properties): use temp_var_name_base to generate temp var names for super transform (#8004)
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.
2024-12-19 02:24:58 +00:00
overlookmotel
87ea928e17 test(transformer/class-properties): failing test for super.prop as assignment target (#8005)
Add failing test for syntax we can't support yet.
2024-12-18 19:07:24 +00:00
Dunqing
3ea4109d14 feat(transformer/class-properties): transform super update expressions within static prop initializer (#7997) 2024-12-18 18:29:05 +00:00
overlookmotel
5cf253c216 test(transformer/class-properties): more testing for assignment to super[prop] (#7992)
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. 🤔
2024-12-18 12:49:42 +00:00
Dunqing
cc57db38e1 feat(transformer/class-properties): transform super assignment expressions within static prop initializer (#7991)
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
2024-12-18 11:28:39 +00:00
Dunqing
e3d0889009 test(transformer/class-properties): add static super tagged template test (#7964)
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`
2024-12-18 10:25:21 +00:00
overlookmotel
bb3806554f fix(transformer/class-properties): do not transform super.prop in nested method within static prop initializer (#7978)
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;
      }
    };
  };
}
```
2024-12-18 03:00:04 +00:00
Dunqing
14c51ffa1d fix(semantic): remove inherting ScopeFlags::Modifier from parent scope (#7932)
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
2024-12-16 11:26:12 +00:00
overlookmotel
80d0b3e10f perf(transformer/class-properties): fast path for instance prop initializer scope re-parenting (#7901)
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.
2024-12-15 01:53:13 +00:00
overlookmotel
feac02e65b feat(transformer/class-properties): only rename symbols if necessary (#7896)
#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.
2024-12-15 01:53:13 +00:00
overlookmotel
e76fbb0721 fix(transformer/class-properties): fix symbol clashes in instance prop initializers (#7872)
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
  }
}
```
2024-12-15 01:53:12 +00:00
overlookmotel
0804916b28 test(transformer): make update fixtures script .mjs (#7892)
`.mjs` to match `reporter.mjs` in same directory.
2024-12-14 15:29:21 +00:00
overlookmotel
3858221f45 refactor(global): sort imports (#7883)
Pure refactor. Re-order imports for clarity:

1. `std`
2. External crates
3. `oxc_*` crates
4. Current crate `use crate::...`
5. Super `use super::...`
6. Local modules

This order is from "furthest away" to "closest". This makes it clearer to see what is coming from where.

`cargo +nightly fmt` (#7877) did a lot of the work, but unfortunately `rustfmt` does not have an option to (a) put workspace crates in a separate block from external crates and (b) move `mod` statements to after `use` statements.
2024-12-14 15:07:21 +00:00
Boshen
7fb9d47460 style(rust): cargo +nightly fmt (#7877) 2024-12-14 06:03:31 +00:00
overlookmotel
588df9f366 test(transformer): transformer conformance runner --override output with spaces not tabs (#7865)
When running `just test-transform --override`, generate override files with indentation as double spaces, instead of tabs. This matches our convention for formatting JS files.
2024-12-14 04:57:00 +00:00
overlookmotel
c0576faf80 fix(transformer/class-properties): use UID for args in created class constructor (#7866)
When creating class constructor for a class which has super class, use UID `_args` for temp var (rather than `args`). This avoids shadowing a var called `args` used in an instance property initializer.

This diverges from Babel. Babel uses `args` unless it finds a var called `args` in an instance property initializer. But searching the AST of initializers can be fairly expensive, so it's better to skip it. The overrides for test fixtures included in this PR are just to account for that difference.
2024-12-14 04:18:48 +00:00
overlookmotel
d660d8d12d fix(transformer/optional-chaining): do not create unused reference when noDocumentAll assumption (#7847)
Similar to #7832. Only create an `IdentifierReference` if it's going to be used in AST.
2024-12-13 14:59:13 +00:00
Dunqing
6bc530d2e2 feat(transformer/class-properties): transform super call expression that is inside static prop initializer (#7831) 2024-12-13 13:47:38 +00:00
Dunqing
4920c6a455 fix(transformer/optional-chaining): avoid creating a useless reference when noDocumentAll is true (#7832) 2024-12-13 13:28:37 +00:00
overlookmotel
14896cb318 fix(transformer/class-properties): create temp vars in correct scope (#7824)
Create `var` temp vars in current *hoist* scope, not current scope.
2024-12-13 04:04:45 +00:00
Yunfei He
9479e2b0a2
fix(semantic): missing references when export {} references a type-only binding and a normal (#7812)
https://playground.oxc.rs/#eNpdTzEOgzAM/AryzFAqdUHq2rlD1YklUIMihTiyTQGh/L0BBEMn31l35/MCDZTQkBfNXmRE3xbHQKzZPSsqX3mcNrZkOgfcJU+mIPmfPEIOBOUCPPh1yOzVTFAqD5iDs14PLA0FPMnc1+QOpmy8tMT9vog5BMOCnAITXkMOfCq3BajhDtMFQLleihskRUMf7HDtkkhvvW3tYU7vKpN7OBpX8xe5JkmVWuMEY4w/P71iMw==

Current:

<img width="876" alt="image"
src="https://github.com/user-attachments/assets/58327920-44ef-469d-8c7c-a2d7b17da717"
/>


Expected:


https://babeljs.io/repl#?browsers=&build=&builtIns=false&corejs=false&spec=false&loose=false&code_lz=MYewdgzgLgBAKiAhtAagSwKYHcAOIBOsAvDAIwBQ5UAnjhvEtAAr4g4QwkXkYAeehGAG8YNOg2RQWbCABoJqTLgKwAvkA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Ctypescript&prettier=false&targets=&version=7.26.4&externalPlugins=&assumptions=%7B%7D

<img width="877" alt="image"
src="https://github.com/user-attachments/assets/9b847baa-5b5a-43be-b77d-d529fb3f8026"
/>

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dunqing <dengqing0821@gmail.com>
2024-12-13 12:00:58 +08:00
overlookmotel
25bb6daa40 fix(transformer/class-properties): fix ScopeIds in instance prop initializers (#7823)
Code in instance property initializers moves from class body into constructor, or a `_super` function. Update parent `ScopeId`s for first level scopes in initializers.
2024-12-13 03:21:37 +00:00
Dunqing
e727ae9698 feat(transformer/class-properties): transform super member expressions that are inside static prop initializer (#7815)
This PR support for transforming `super.prop` to  `babelHelpers.superPropGet(_B, "prop", _B)`

Input:
```js
class A {
  static prop = 1;
}

class B extends A {
  static prop = 2;
  static propA = super.prop;
  static getPropA = () => super.prop;
}
```

Output:
```js
var _B;
class A {}
babelHelpers.defineProperty(A, "prop", 1);
class B extends A {}
_B = B;
babelHelpers.defineProperty(B, "prop", 2);
babelHelpers.defineProperty(B, "propA", babelHelpers.superPropGet(_B, "prop", _B));
babelHelpers.defineProperty(B, "getPropA", () => babelHelpers.superPropGet(_B, "prop", _B));
```
2024-12-13 02:33:37 +00:00
Dunqing
b290ebd2b0 refactor(transformer): handle <CWD> in test runner (#7799)
We should move the handling of  `<CWD>` to the test runner because this is just only used in testing, and it causes us always get a path by `self.ctx.source_path` like `<CWD>/xxx/xxx.js`, we should get a real path for this.
2024-12-12 17:22:01 +00:00
overlookmotel
d14d360061 test(transformer): remove dead code from fixtures update script (#7808)
Follow-up after #7771 and #7779. Remove dead code from transformer fixtures updater script.
2024-12-12 09:27:54 +00:00
Dunqing
74bf141b1a chore(tasks/transform-conformance): update only when the output differs from the original output (#7779)
From `5xx` files changed to `3xx`
2024-12-11 16:26:36 +00:00
Dunqing
4d33ffbbc8 chore(tasks/transform-conformance): support --override flag (#7774)
The `--override` flag used to write the output which is generated by the transformer to the `overrides` folder according to the test path. The acting is similar to the previous `takeover` mode
2024-12-11 16:18:16 +00:00
Dunqing
b089e8b519 chore(tasks/transform-conformance): support override to replace takeover mode (#7771)
This PR does the following things.

1. Move the override output of the `snapshots` folder to the `overrides` folder.
2. Support `override` mode to replace `takeover` mode
3. The `update_fixtures.js` no longer uses `overrides`'s `output.js` to replace Babel's `output.js`.

### How does `override` mode work?

When running each test, it checks whether an output file for that test exists in the ⁠`overrides` directory. If it does, the output file will be used to compare with the transformed code.
2024-12-11 16:18:14 +00:00
overlookmotel
450bb334da test(transformer): conformance runner use HelperLoaderMode::External in takeover mode (#7807)
In "takeover" mode, transformer conformance test runner was using `HelperLoaderMode::Runtime`. Switch this to `HelperLoaderMode::External` to match standard test runner mode.
2024-12-11 16:07:01 +00:00
Dunqing
2964a61546 fix(transformer/class-properties): unwrap failed when private field expression doesn't contain optional expression in ChainExpression (#7798)
The root cause is due to transform wrongly a PrivateFieldExpression that doesn't contain any optional expression, so call `to_member_expression_mut` causes unwrap to fail.  I have fixed the incorrect transform and changed `to_member_expression_mut` to `as_member_expression_mut`.
2024-12-11 11:32:21 +00:00
Dunqing
6fa6785d0d fix(transformer/class-properties): panic when the callee or member is ParenthesisExpression or TS-syntax expressions. (#7795)
We need to call `get_inner_expression_mut` to get actual expressions that we need to deal with
2024-12-11 11:15:20 +00:00
overlookmotel
bb22c67974 fix(transformer/class-properties): fix ScopeIds in static prop initializers (#7791)
Code in static property initializers moves from inside the class to outside. Update parent `ScopeId`s for first level scopes in initializers.
2024-12-11 03:18:29 +00:00