Skip to content

Commit ee6fa4a

Browse files
committed
save
1 parent cb1faec commit ee6fa4a

6 files changed

Lines changed: 40 additions & 529 deletions

File tree

crates/oxc_angular_compiler/src/component/decorator.rs

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,48 +1088,6 @@ pub fn collect_member_decorator_spans(class: &Class<'_>, spans: &mut std::vec::V
10881088
}
10891089
}
10901090

1091-
/// Collect spans of uninitialized class field declarations for stripping.
1092-
///
1093-
/// TypeScript class field declarations like `name: string;` without initializers are
1094-
/// type-only annotations that have no runtime effect. They should be stripped from
1095-
/// the output to match TypeScript's emit behavior.
1096-
///
1097-
/// Only collects:
1098-
/// - Non-static property definitions without an initializer (e.g., `name: string;`)
1099-
///
1100-
/// Does NOT collect:
1101-
/// - Fields with initializers (e.g., `name = 'value';`) - these have runtime values
1102-
/// - Static fields (e.g., `static version: string;`) - handled separately
1103-
/// - Methods or accessors - they have runtime bodies
1104-
/// - Decorated fields - Angular may need the field structure
1105-
///
1106-
/// These spans are used by `transform.rs` to remove the declarations from the
1107-
/// source text during transformation.
1108-
pub fn collect_uninitialized_field_spans(class: &Class<'_>, spans: &mut std::vec::Vec<Span>) {
1109-
for element in &class.body.body {
1110-
if let ClassElement::PropertyDefinition(prop) = element {
1111-
// Skip static fields - they're handled differently
1112-
if prop.r#static {
1113-
continue;
1114-
}
1115-
1116-
// Skip fields with initializers - they have runtime values
1117-
if prop.value.is_some() {
1118-
continue;
1119-
}
1120-
1121-
// Skip decorated fields - Angular may need them
1122-
if !prop.decorators.is_empty() {
1123-
continue;
1124-
}
1125-
1126-
// This is an uninitialized, non-static, non-decorated field declaration
1127-
// (e.g., `name: string;`) - it should be stripped
1128-
spans.push(prop.span);
1129-
}
1130-
}
1131-
}
1132-
11331091
#[cfg(test)]
11341092
mod tests {
11351093
use super::*;

crates/oxc_angular_compiler/src/component/transform.rs

Lines changed: 40 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_hash::FxHashMap;
1818
use super::cross_file_elision::CrossFileAnalyzer;
1919
use super::decorator::{
2020
collect_constructor_decorator_spans, collect_member_decorator_spans,
21-
collect_uninitialized_field_spans, extract_component_metadata, find_component_decorator_span,
21+
extract_component_metadata, find_component_decorator_span,
2222
};
2323
use super::definition::{const_value_to_expression, generate_component_definitions};
2424
use super::import_elision::{ImportElisionAnalyzer, filter_imports};
@@ -121,28 +121,6 @@ pub struct TransformOptions {
121121
/// Contains property bindings, attribute bindings, and event listeners.
122122
pub host: Option<HostMetadataInput>,
123123

124-
/// Use ES2022 class field semantics for static field emission.
125-
///
126-
/// When `true` (default), emits static fields inside the class body:
127-
/// ```js
128-
/// class MyComponent {
129-
/// static ɵfac = ...;
130-
/// static ɵcmp = ...;
131-
/// }
132-
/// ```
133-
///
134-
/// When `false`, emits static fields as external property assignments:
135-
/// ```js
136-
/// class MyComponent { }
137-
/// MyComponent.ɵfac = ...;
138-
/// MyComponent.ɵcmp = ...;
139-
/// ```
140-
///
141-
/// This corresponds to TypeScript's `useDefineForClassFields` compiler option.
142-
/// Projects targeting older browsers or using `useDefineForClassFields: false`
143-
/// should set this to `false` for compatibility.
144-
pub use_define_for_class_fields: bool,
145-
146124
/// Enable cross-file import elision analysis.
147125
///
148126
/// When true, resolves imports to source files to check if exports are type-only.
@@ -225,7 +203,6 @@ impl Default for TransformOptions {
225203
change_detection: None,
226204
preserve_whitespaces: None,
227205
host: None,
228-
use_define_for_class_fields: true, // ES2022 style by default
229206
// Cross-file elision options (feature-gated)
230207
#[cfg(feature = "cross_file_elision")]
231208
cross_file_elision: false,
@@ -755,23 +732,12 @@ pub fn transform_angular_file(
755732
// Order: ɵfac BEFORE ɵcmp (Angular convention).
756733
// External declarations (child view functions, constants) go BEFORE the class.
757734
// Note: The /*@__PURE__*/ annotation is already included in cmp_js by the emitter.
758-
let property_assignments = if options.use_define_for_class_fields {
759-
// ES2022 style: static fields INSIDE the class body
760-
format!(
761-
"static ɵfac = {};\nstatic ɵcmp = {};",
762-
compilation_result.fac_js,
763-
compilation_result.cmp_js
764-
)
765-
} else {
766-
// ES5 style: external property assignments AFTER the class
767-
format!(
768-
"{}.ɵfac = {};\n{}.ɵcmp = {};",
769-
class_name,
770-
compilation_result.fac_js,
771-
class_name,
772-
compilation_result.cmp_js
773-
)
774-
};
735+
// ES2022 style: static fields INSIDE the class body
736+
let property_assignments = format!(
737+
"static ɵfac = {};\nstatic ɵcmp = {};",
738+
compilation_result.fac_js,
739+
compilation_result.cmp_js
740+
);
775741

776742
// External declarations and HMR code go after the class
777743
let mut external_decls = compilation_result.declarations_js.clone();
@@ -840,23 +806,12 @@ pub fn transform_angular_file(
840806
let emitter = JsEmitter::new();
841807
let class_name = directive_metadata.name.to_string();
842808
// Order: ɵfac BEFORE ɵdir (Angular convention)
843-
let property_assignments = if options.use_define_for_class_fields {
844-
// ES2022 style: static fields INSIDE the class body
845-
format!(
846-
"static ɵfac = {};\nstatic ɵdir = {};",
847-
emitter.emit_expression(&definitions.fac_definition),
848-
emitter.emit_expression(&definitions.dir_definition)
849-
)
850-
} else {
851-
// ES5 style: external property assignments AFTER the class
852-
format!(
853-
"{}.ɵfac = {};\n{}.ɵdir = {};",
854-
class_name,
855-
emitter.emit_expression(&definitions.fac_definition),
856-
class_name,
857-
emitter.emit_expression(&definitions.dir_definition)
858-
)
859-
};
809+
// ES2022 style: static fields INSIDE the class body
810+
let property_assignments = format!(
811+
"static ɵfac = {};\nstatic ɵdir = {};",
812+
emitter.emit_expression(&definitions.fac_definition),
813+
emitter.emit_expression(&definitions.dir_definition)
814+
);
860815

861816
// Track definitions by class name (position is recalculated later)
862817
class_definitions.insert(class_name, (property_assignments, String::new()));
@@ -888,23 +843,12 @@ pub fn transform_angular_file(
888843
// Emit both ɵfac and ɵprov definitions.
889844
// IMPORTANT: ɵfac must come BEFORE ɵprov because ɵprov's factory
890845
// property references MyClass.ɵfac, which must already be defined.
891-
let property_assignments = if options.use_define_for_class_fields {
892-
// ES2022 style: static fields INSIDE the class body
893-
format!(
894-
"static ɵfac = {};\nstatic ɵprov = {};",
895-
emitter.emit_expression(&definition.fac_definition),
896-
emitter.emit_expression(&definition.prov_definition)
897-
)
898-
} else {
899-
// ES5 style: external property assignments AFTER the class
900-
format!(
901-
"{}.ɵfac = {};\n{}.ɵprov = {};",
902-
class_name,
903-
emitter.emit_expression(&definition.fac_definition),
904-
class_name,
905-
emitter.emit_expression(&definition.prov_definition)
906-
)
907-
};
846+
// ES2022 style: static fields INSIDE the class body
847+
let property_assignments = format!(
848+
"static ɵfac = {};\nstatic ɵprov = {};",
849+
emitter.emit_expression(&definition.fac_definition),
850+
emitter.emit_expression(&definition.prov_definition)
851+
);
908852

909853
// Track definitions by class name (position is recalculated later)
910854
class_definitions.insert(class_name, (property_assignments, String::new()));
@@ -933,23 +877,12 @@ pub fn transform_angular_file(
933877
let emitter = JsEmitter::new();
934878
let class_name = pipe_metadata.class_name.to_string();
935879
// Order: ɵfac BEFORE ɵpipe (Angular convention)
936-
let property_assignments = if options.use_define_for_class_fields {
937-
// ES2022 style: static fields INSIDE the class body
938-
format!(
939-
"static ɵfac = {};\nstatic ɵpipe = {};",
940-
emitter.emit_expression(&definition.fac_definition),
941-
emitter.emit_expression(&definition.pipe_definition)
942-
)
943-
} else {
944-
// ES5 style: external property assignments AFTER the class
945-
format!(
946-
"{}.ɵfac = {};\n{}.ɵpipe = {};",
947-
class_name,
948-
emitter.emit_expression(&definition.fac_definition),
949-
class_name,
950-
emitter.emit_expression(&definition.pipe_definition)
951-
)
952-
};
880+
// ES2022 style: static fields INSIDE the class body
881+
let property_assignments = format!(
882+
"static ɵfac = {};\nstatic ɵpipe = {};",
883+
emitter.emit_expression(&definition.fac_definition),
884+
emitter.emit_expression(&definition.pipe_definition)
885+
);
953886

954887
// Track definitions by class name (position is recalculated later)
955888
class_definitions.insert(class_name, (property_assignments, String::new()));
@@ -980,26 +913,13 @@ pub fn transform_angular_file(
980913

981914
// Generate static field definitions
982915
// Order: ɵfac BEFORE ɵmod BEFORE ɵinj (Angular convention)
983-
let property_assignments = if options.use_define_for_class_fields {
984-
// ES2022 style: static fields INSIDE the class body
985-
format!(
986-
"static ɵfac = {};\nstatic ɵmod = {};\nstatic ɵinj = {};",
987-
emitter.emit_expression(&definition.fac_definition),
988-
emitter.emit_expression(&definition.mod_definition),
989-
emitter.emit_expression(&definition.inj_definition)
990-
)
991-
} else {
992-
// ES5 style: external property assignments AFTER the class
993-
format!(
994-
"{}.ɵfac = {};\n{}.ɵmod = {};\n{}.ɵinj = {};",
995-
class_name,
996-
emitter.emit_expression(&definition.fac_definition),
997-
class_name,
998-
emitter.emit_expression(&definition.mod_definition),
999-
class_name,
1000-
emitter.emit_expression(&definition.inj_definition)
1001-
)
1002-
};
916+
// ES2022 style: static fields INSIDE the class body
917+
let property_assignments = format!(
918+
"static ɵfac = {};\nstatic ɵmod = {};\nstatic ɵinj = {};",
919+
emitter.emit_expression(&definition.fac_definition),
920+
emitter.emit_expression(&definition.mod_definition),
921+
emitter.emit_expression(&definition.inj_definition)
922+
);
1003923

1004924
// Collect any side-effect statements as external declarations
1005925
let mut external_decls = String::new();
@@ -1019,27 +939,6 @@ pub fn transform_angular_file(
1019939
}
1020940
}
1021941

1022-
// Collect uninitialized field spans from ALL classes (including non-Angular-decorated ones).
1023-
// TypeScript strips field declarations like `name: string;` (without initializers) because
1024-
// they're type-only annotations with no runtime effect.
1025-
for stmt in &parser_ret.program.body {
1026-
let class = match stmt {
1027-
Statement::ClassDeclaration(class) => Some(class.as_ref()),
1028-
Statement::ExportDefaultDeclaration(export) => match &export.declaration {
1029-
ExportDefaultDeclarationKind::ClassDeclaration(class) => Some(class.as_ref()),
1030-
_ => None,
1031-
},
1032-
Statement::ExportNamedDeclaration(export) => match &export.declaration {
1033-
Some(Declaration::ClassDeclaration(class)) => Some(class.as_ref()),
1034-
_ => None,
1035-
},
1036-
_ => None,
1037-
};
1038-
if let Some(class) = class {
1039-
collect_uninitialized_field_spans(class, &mut decorator_spans_to_remove);
1040-
}
1041-
}
1042-
1043942
// 5. Generate output code by modifying the original source
1044943
// We use string manipulation instead of oxc_codegen to preserve
1045944
// the original code structure and avoid decorator placement issues.
@@ -1070,9 +969,6 @@ pub fn transform_angular_file(
1070969
_ => None,
1071970
};
1072971
if let Some(class) = class {
1073-
// Collect uninitialized field spans for ALL classes (TypeScript stripping)
1074-
collect_uninitialized_field_spans(class, &mut new_decorator_spans);
1075-
1076972
// Check for component, directive, injectable, pipe, or ngmodule decorators
1077973
// and collect associated parameter/member decorator spans
1078974
if let Some(span) = find_component_decorator_span(class) {
@@ -1228,30 +1124,16 @@ pub fn transform_angular_file(
12281124

12291125
for (class_name, class_start, class_body_end) in class_positions {
12301126
if let Some((property_assignments, external_decls)) = class_definitions.get(&class_name) {
1231-
if options.use_define_for_class_fields {
1232-
// ES2022 style: Property assignments go INSIDE the class body as static fields
1233-
// class_body_end points right after the `}`, so we insert at position - 1 (before the `}`)
1234-
let insert_pos = (class_body_end - 1) as usize;
1127+
// ES2022 style: Property assignments go INSIDE the class body as static fields
1128+
// class_body_end points right after the `}`, so we insert at position - 1 (before the `}`)
1129+
let insert_pos = (class_body_end - 1) as usize;
12351130

1236-
// Build the insertion string: static fields go inside the class body
1237-
let insertion = format!("\n{}\n", property_assignments);
1131+
// Build the insertion string: static fields go inside the class body
1132+
let insertion = format!("\n{}\n", property_assignments);
12381133

1239-
// Insert static fields before the closing brace
1240-
if insert_pos <= final_code.len() {
1241-
final_code.insert_str(insert_pos, &insertion);
1242-
}
1243-
} else {
1244-
// ES5 style: Property assignments go AFTER the class as external assignments
1245-
// class_body_end points right after the `}`, so we insert there
1246-
let insert_pos = class_body_end as usize;
1247-
1248-
// Build the insertion string: external assignments after the class
1249-
let insertion = format!("\n{}", property_assignments);
1250-
1251-
// Insert after the class closing brace
1252-
if insert_pos <= final_code.len() {
1253-
final_code.insert_str(insert_pos, &insertion);
1254-
}
1134+
// Insert static fields before the closing brace
1135+
if insert_pos <= final_code.len() {
1136+
final_code.insert_str(insert_pos, &insertion);
12551137
}
12561138

12571139
// External declarations (constants, child views) go BEFORE the class

0 commit comments

Comments
 (0)