Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/oxc_transformer/src/es2022/class_properties/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ impl<'a> ClassProperties<'a, '_> {
}
}

// When `self.set_public_class_fields` is true, we don't need to convert instance properties
// without initializers, that means `instance_prop_count != 0` but `instance_inits` may be empty.
if instance_inits.is_empty() {
return;
}

// Scope that instance property initializers will be inserted into.
// This is usually class constructor, but can also be a `_super` function which is created.
let instance_inits_scope_id;
Expand Down
34 changes: 26 additions & 8 deletions crates/oxc_transformer/src/es2022/class_properties/prop_decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,20 @@ impl<'a> ClassProperties<'a, '_> {
ctx: &mut TraverseCtx<'a>,
) {
// Get value
let value = prop.value.take().unwrap_or_else(|| ctx.ast.void_0(SPAN));
let value = prop.value.take();

let init_expr = if let PropertyKey::PrivateIdentifier(ident) = &mut prop.key {
let value = value.unwrap_or_else(|| ctx.ast.void_0(SPAN));
self.create_private_instance_init_assignment(ident, value, ctx)
} else {
let value = match value {
Some(value) => value,
// Do not need to convert property to `assignee.prop = void 0` if no initializer exists.
// This is to align `TypeScript` with `useDefineForClassFields: false`.
None if self.private_fields_as_properties => return,
None => ctx.ast.void_0(SPAN),
};

// Convert to assignment or `_defineProperty` call, depending on `loose` option
let this = ctx.ast.expression_this(SPAN);
self.create_init_assignment(prop, value, this, false, ctx)
Expand Down Expand Up @@ -85,17 +94,23 @@ impl<'a> ClassProperties<'a, '_> {
// Get value.
// Transform it to replace `this` and references to class name with temp var for class.
// Also transform `super`.
let value = match prop.value.take() {
Some(mut value) => {
self.transform_static_initializer(&mut value, ctx);
value
}
None => ctx.ast.void_0(SPAN),
};
let value = prop.value.take().map(|mut value| {
self.transform_static_initializer(&mut value, ctx);
value
});

if let PropertyKey::PrivateIdentifier(ident) = &mut prop.key {
let value = value.unwrap_or_else(|| ctx.ast.void_0(SPAN));
self.insert_private_static_init_assignment(ident, value, ctx);
} else {
let value = match value {
Some(value) => value,
// Do not need to convert property to `assignee.prop = void 0` if no initializer exists.
// This is to align `TypeScript` with `useDefineForClassFields: false`.
None if self.private_fields_as_properties => return,
None => ctx.ast.void_0(SPAN),
};

// Convert to assignment or `_defineProperty` call, depending on `loose` option
let class_details = self.current_class();
let class_binding = if class_details.is_declaration {
Expand Down Expand Up @@ -200,6 +215,9 @@ impl<'a> ClassProperties<'a, '_> {
// Used for both instance and static properties
impl<'a> ClassProperties<'a, '_> {
/// `assignee.prop = value` or `_defineProperty(assignee, "prop", value)`
/// `#[inline]` because the caller has been checked `self.set_public_class_fields`.
/// After inlining, the two `self.set_public_class_fields` checks may be folded into one.
#[inline]
fn create_init_assignment(
&mut self,
prop: &mut PropertyDefinition<'a>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
class C {
constructor(T) {
this.x = void 0;
this.y = 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
class Foo {
constructor() {
this.bar = void 0;
}
}
class Foo { }
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
class C {
constructor() {
this.a = void 0;
}
}
C.b = void 0;
class C { }
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
class Foo {}
Foo.bar = void 0;
6 changes: 5 additions & 1 deletion tasks/transform_conformance/snapshots/babel_exec.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ commit: 578ac4df

node: v22.14.0

Passed: 320 of 406 (78.82%)
Passed: 319 of 406 (78.57%)

Failures:

Expand Down Expand Up @@ -58,6 +58,10 @@ AssertionError: expected function to throw an error, but it didn't
AssertionError: expected '_Class' to be 'Foo' // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-loose-static-infer-name-exec.test.js:8:19

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-loose-static-undefined-exec.test.js
AssertionError: expected false to be true // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-loose-static-undefined-exec.test.js:5:23

./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-static-infer-name-exec.test.js
AssertionError: expected '_Class' to be 'Foo' // Object.is equality
at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-static-infer-name-exec.test.js:9:19
Expand Down
Loading