oxc-project / oxc

⚓ A collection of JavaScript tools written in Rust.
https://oxc.rs
MIT License
12.11k stars 438 forks source link

transformer: helper library #4753

Closed Boshen closed 2 weeks ago

Boshen commented 2 months ago

It's either @babel/helpers or tslib ...

overlookmotel commented 2 months ago

I vote Babel, since we're primarily modelling our transforms on Babel's implementations.

rzvxa commented 2 months ago

I also think using Babel helpers is easier but it's quite chunky, Is there any possibility of forking it in the future so we can strip it down to its bare bones?

Boshen commented 2 months ago

The next task is to figure out how to get our conformance suite to work with this ...

Boshen commented 2 months ago

As it turns out we don't need to inline the helper functions for the test suites

https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-class-properties/test/fixtures/private/call/output.js

var _foo = /*#__PURE__*/new WeakMap();
let Foo = /*#__PURE__*/function () {
  "use strict";

  function Foo() {
    babelHelpers.classCallCheck(this, Foo);
    babelHelpers.classPrivateFieldInitSpec(this, _foo, function () {
      return this;
    });
  }
  return babelHelpers.createClass(Foo, [{
    key: "test",
    value: function test(other) {
      var _other$obj;
      babelHelpers.classPrivateFieldGet2(_foo, this).call(this);
      babelHelpers.classPrivateFieldGet2(_foo, _other$obj = other.obj).call(_other$obj);
    }
  }]);
}();

The relevant functionality we need to port is https://github.com/babel/babel/blob/7edd5082152d6b89e90ae09a533eb725b15902ba/packages/babel-core/src/transformation/file/file.ts#L153-L200

overlookmotel commented 2 months ago

OK great!

I guess we need to add a helpers struct to TransformCtx to centralize this logic.

Shall we put in a basic version for now which always returns a babelHelpers.<helper_name>(...) call, so we can implement plugins and get tests passing? Then we can make it work properly with inline helpers/imports later on. Something like:

struct Helpers<'a>(PhantomData<&'a ()>);

impl<'a> Helpers<'a> {
    fn call(helper_name: Atom<'a>, arguments: Vec<'a, Argument<'a>>, ctx: &mut TraverseCtx<'a>) -> CallExpression<'a>;
    fn call_expr(helper_name: Atom<'a>, arguments: Vec<'a, Argument<'a>>, ctx: &mut TraverseCtx<'a>) -> Expression<'a>;
}

A few notes:

  1. I think we should take Atom<'a> for helper name rather than &str. It's cheaper to create a static Atom in caller with Atom::from("createClass") than having to call ast.atom(helper_name) inside Helpers::call (the latter allocates string into arena, which is unnecessary work).
  2. The &mut TraverseCtx argument is needed to create a Reference for the "babelHelpers" IdentifierReference.
  3. The 'a lifetime on Helpers<'a> is not needed now, but will be later on once Helpers stores state.
Boshen commented 1 month ago

We already have https://github.com/oxc-project/oxc/blob/aeda84f904a6d4ea001bfa021752e64283fc56c4/crates/oxc_transformer/src/es2018/object_rest_spread/object_spread.rs#L83 which breaks monitor-oxc 🤣

/home/runner/work/monitor-oxc/monitor-oxc/node_modules/.pnpm/@aws-sdk+client-cognito-identity@3.637.0/node_modules/@aws-sdk/client-cognito-identity/dist-cjs/index.js:795
var _CreateIdentityPoolCommand = class _CreateIdentityPoolCommand extends (import_smithy_client.Command.classBuilder().ep(babelHelpers.objectSpread2({}, commonParams)).m(function(Command, cs, config, o) {
                                                                                                                          ^

ReferenceError: babelHelpers is not defined
7086cmd commented 1 month ago

Subsequently, the helper code will be “replaced” in the following location: https://github.com/babel/babel/blob/main/packages/babel-helpers/src/helpers-generated.ts. One of the helper files is in human-readable JavaScript (with indents and visible variables), while the other is gzipped and located in the helpers-generated.ts file.

It appears that the we can split the process into stages, or can we pass the helper in Codegen?