1use oxc_ast::{NONE, ast::*};
5use oxc_span::{SPAN, Span};
6use oxc_syntax::reference::ReferenceFlags;
7
8use crate::{
9 common::helper_loader::{Helper, helper_call_expr},
10 context::TraverseCtx,
11 utils::ast_builder::create_assignment,
12};
13
14use super::{
15 ClassProperties,
16 utils::{create_underscore_ident_name, create_variable_declaration},
17};
18
19impl<'a> ClassProperties<'a> {
21 pub(super) fn convert_instance_property(
24 &mut self,
25 prop: &mut PropertyDefinition<'a>,
26 instance_inits: &mut Vec<Expression<'a>>,
27 ctx: &mut TraverseCtx<'a>,
28 ) {
29 let value = prop.value.take();
31
32 let span = prop.span;
33 let init_expr = if let PropertyKey::PrivateIdentifier(ident) = &mut prop.key {
34 let value = value.unwrap_or_else(|| ctx.ast.void_0(SPAN));
35 self.create_private_instance_init_assignment(ident, value, span, ctx)
36 } else {
37 let value = match value {
38 Some(value) => value,
39 None if self.set_public_class_fields
44 && self.remove_class_fields_without_initializer =>
45 {
46 return;
47 }
48 None => ctx.ast.void_0(SPAN),
49 };
50
51 let this = ctx.ast.expression_this(SPAN);
53 self.create_init_assignment(prop, value, this, false, ctx)
54 };
55 instance_inits.push(init_expr);
56 }
57
58 fn create_private_instance_init_assignment(
63 &self,
64 ident: &PrivateIdentifier<'a>,
65 value: Expression<'a>,
66 span: Span,
67 ctx: &mut TraverseCtx<'a>,
68 ) -> Expression<'a> {
69 if self.private_fields_as_properties {
70 let this = ctx.ast.expression_this(SPAN);
71 self.create_private_init_assignment_loose(ident, value, this, span, ctx)
72 } else {
73 self.create_private_instance_init_assignment_not_loose(ident, value, span, ctx)
74 }
75 }
76
77 fn create_private_instance_init_assignment_not_loose(
79 &self,
80 ident: &PrivateIdentifier<'a>,
81 value: Expression<'a>,
82 span: Span,
83 ctx: &mut TraverseCtx<'a>,
84 ) -> Expression<'a> {
85 let private_props = self.current_class().private_props.as_ref().unwrap();
86 let prop = &private_props[&ident.name];
87 let arguments = ctx.ast.vec_from_array([
88 Argument::from(ctx.ast.expression_this(SPAN)),
89 Argument::from(prop.binding.create_read_expression(ctx)),
90 Argument::from(value),
91 ]);
92 helper_call_expr(Helper::ClassPrivateFieldInitSpec, span, arguments, ctx)
93 }
94}
95
96impl<'a> ClassProperties<'a> {
98 pub(super) fn convert_static_property(
101 &mut self,
102 prop: &mut PropertyDefinition<'a>,
103 ctx: &mut TraverseCtx<'a>,
104 ) {
105 let value = prop.value.take().map(|mut value| {
109 self.transform_static_initializer(&mut value, ctx);
110 value
111 });
112
113 let span = prop.span;
114 if let PropertyKey::PrivateIdentifier(ident) = &mut prop.key {
115 let value = value.unwrap_or_else(|| ctx.ast.void_0(SPAN));
116 self.insert_private_static_init_assignment(ident, value, span, ctx);
117 } else {
118 let value = match value {
119 Some(value) => value,
120 None if self.set_public_class_fields
125 && self.remove_class_fields_without_initializer =>
126 {
127 return self.extract_computed_key(prop, ctx);
128 }
129 None => ctx.ast.void_0(SPAN),
130 };
131
132 let class_details = self.current_class();
134 let class_binding = if class_details.is_declaration {
135 class_details.bindings.name.as_ref().unwrap()
138 } else {
139 class_details.bindings.temp.as_ref().unwrap()
141 };
142
143 let assignee = class_binding.create_read_expression(ctx);
144 let init_expr = self.create_init_assignment(prop, value, assignee, true, ctx);
145 self.insert_expr_after_class(init_expr, ctx);
146 }
147 }
148
149 fn insert_private_static_init_assignment(
158 &mut self,
159 ident: &PrivateIdentifier<'a>,
160 value: Expression<'a>,
161 span: Span,
162 ctx: &mut TraverseCtx<'a>,
163 ) {
164 if self.private_fields_as_properties {
165 self.insert_private_static_init_assignment_loose(ident, value, span, ctx);
166 } else {
167 self.insert_private_static_init_assignment_not_loose(ident, value, ctx);
168 }
169 }
170
171 fn insert_private_static_init_assignment_loose(
174 &mut self,
175 ident: &PrivateIdentifier<'a>,
176 value: Expression<'a>,
177 span: Span,
178 ctx: &mut TraverseCtx<'a>,
179 ) {
180 let class_details = self.current_class();
182 let class_binding = if class_details.is_declaration {
183 class_details.bindings.name.as_ref().unwrap()
186 } else {
187 class_details.bindings.temp.as_ref().unwrap()
189 };
190
191 let assignee = class_binding.create_read_expression(ctx);
192 let assignment =
193 self.create_private_init_assignment_loose(ident, value, assignee, span, ctx);
194 self.insert_expr_after_class(assignment, ctx);
195 }
196
197 fn insert_private_static_init_assignment_not_loose(
202 &mut self,
203 ident: &PrivateIdentifier<'a>,
204 value: Expression<'a>,
205 ctx: &mut TraverseCtx<'a>,
206 ) {
207 let property = ctx.ast.object_property_kind_object_property(
209 SPAN,
210 PropertyKind::Init,
211 PropertyKey::StaticIdentifier(ctx.ast.alloc(create_underscore_ident_name(ctx))),
212 value,
213 false,
214 false,
215 false,
216 );
217 let obj = ctx.ast.expression_object(SPAN, ctx.ast.vec1(property));
218
219 let class_details = self.current_class();
221 let private_props = class_details.private_props.as_ref().unwrap();
222 let prop_binding = &private_props[&ident.name].binding;
223
224 if class_details.is_declaration {
225 let var_decl = create_variable_declaration(prop_binding, obj, ctx);
227 self.insert_after_stmts.push(var_decl);
228 } else {
229 let assignment = create_assignment(prop_binding, obj, SPAN, ctx);
231 self.insert_after_exprs.push(assignment);
232 }
233 }
234}
235
236impl<'a> ClassProperties<'a> {
238 #[inline]
242 fn create_init_assignment(
243 &mut self,
244 prop: &mut PropertyDefinition<'a>,
245 value: Expression<'a>,
246 assignee: Expression<'a>,
247 is_static: bool,
248 ctx: &mut TraverseCtx<'a>,
249 ) -> Expression<'a> {
250 if self.set_public_class_fields {
251 self.create_init_assignment_loose(prop, value, assignee, is_static, ctx)
253 } else {
254 self.create_init_assignment_not_loose(prop, value, assignee, is_static, ctx)
256 }
257 }
258
259 fn create_init_assignment_loose(
261 &mut self,
262 prop: &mut PropertyDefinition<'a>,
263 value: Expression<'a>,
264 assignee: Expression<'a>,
265 is_static: bool,
266 ctx: &mut TraverseCtx<'a>,
267 ) -> Expression<'a> {
268 let needs_define = |name: &str| is_static && (name == "name" || name == "length");
270
271 let left = match &mut prop.key {
272 PropertyKey::StaticIdentifier(ident) => {
273 if needs_define(&ident.name) {
274 return self
275 .create_init_assignment_not_loose(prop, value, assignee, is_static, ctx);
276 }
277 ctx.ast.member_expression_static(SPAN, assignee, ident.as_ref().clone(), false)
278 }
279 PropertyKey::StringLiteral(str_lit) if needs_define(&str_lit.value) => {
280 return self
281 .create_init_assignment_not_loose(prop, value, assignee, is_static, ctx);
282 }
283 key @ match_expression!(PropertyKey) => {
284 let key = key.to_expression_mut();
285 let key = self.create_computed_key_temp_var_if_required(key, is_static, ctx);
290 ctx.ast.member_expression_computed(SPAN, assignee, key, false)
291 }
292 PropertyKey::PrivateIdentifier(_) => {
293 unreachable!();
295 }
296 };
297
298 ctx.ast.expression_assignment(
299 prop.span,
300 AssignmentOperator::Assign,
301 AssignmentTarget::from(left),
302 value,
303 )
304 }
305
306 fn create_init_assignment_not_loose(
308 &mut self,
309 prop: &mut PropertyDefinition<'a>,
310 value: Expression<'a>,
311 assignee: Expression<'a>,
312 is_static: bool,
313 ctx: &mut TraverseCtx<'a>,
314 ) -> Expression<'a> {
315 let key = match &mut prop.key {
316 PropertyKey::StaticIdentifier(ident) => {
317 ctx.ast.expression_string_literal(ident.span, ident.name, None)
318 }
319 key @ match_expression!(PropertyKey) => {
320 let key = key.to_expression_mut();
321 self.create_computed_key_temp_var_if_required(key, is_static, ctx)
326 }
327 PropertyKey::PrivateIdentifier(_) => {
328 unreachable!();
330 }
331 };
332
333 let arguments = ctx.ast.vec_from_array([
334 Argument::from(assignee),
335 Argument::from(key),
336 Argument::from(value),
337 ]);
338 helper_call_expr(Helper::DefineProperty, prop.span, arguments, ctx)
339 }
340
341 fn create_private_init_assignment_loose(
343 &self,
344 ident: &PrivateIdentifier<'a>,
345 value: Expression<'a>,
346 assignee: Expression<'a>,
347 span: Span,
348 ctx: &mut TraverseCtx<'a>,
349 ) -> Expression<'a> {
350 let object_name = ctx.ast.ident("Object");
352 let object_symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), object_name);
353 let object =
354 ctx.create_ident_expr(SPAN, object_name, object_symbol_id, ReferenceFlags::Read);
355 let property = ctx.ast.identifier_name(SPAN, "defineProperty");
356 let callee =
357 Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false));
358
359 let prop_def = ctx.ast.expression_object(
361 SPAN,
362 ctx.ast.vec_from_array([
363 ctx.ast.object_property_kind_object_property(
364 SPAN,
365 PropertyKind::Init,
366 ctx.ast.property_key_static_identifier(SPAN, Str::from("writable")),
367 ctx.ast.expression_boolean_literal(SPAN, true),
368 false,
369 false,
370 false,
371 ),
372 ctx.ast.object_property_kind_object_property(
373 SPAN,
374 PropertyKind::Init,
375 ctx.ast.property_key_static_identifier(SPAN, Str::from("value")),
376 value,
377 false,
378 false,
379 false,
380 ),
381 ]),
382 );
383
384 let private_props = self.current_class().private_props.as_ref().unwrap();
385 let prop_binding = &private_props[&ident.name].binding;
386 let arguments = ctx.ast.vec_from_array([
387 Argument::from(assignee),
388 Argument::from(prop_binding.create_read_expression(ctx)),
389 Argument::from(prop_def),
390 ]);
391 ctx.ast.expression_call(span, callee, NONE, arguments, false)
392 }
393}