Skip to content

Commit f125abf

Browse files
committed
transform
1 parent db33fc4 commit f125abf

File tree

13 files changed

+1937
-123
lines changed

13 files changed

+1937
-123
lines changed

crates/oxc_angular_compiler/src/component/decorator.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use oxc_span::{Atom, Span};
1212
use super::metadata::{
1313
ChangeDetectionStrategy, ComponentMetadata, HostMetadata, ViewEncapsulation,
1414
};
15+
use crate::output::oxc_converter::convert_oxc_expression;
1516

1617
/// Extract component metadata from a class with decorators.
1718
///
@@ -124,6 +125,24 @@ pub fn extract_component_metadata<'a>(
124125
metadata.preserve_whitespaces =
125126
extract_boolean_value(&prop.value).unwrap_or(false);
126127
}
128+
"animations" => {
129+
// Extract animations expression as full OutputExpression
130+
// Handles both identifier references and complex array expressions
131+
metadata.animations = convert_oxc_expression(allocator, &prop.value);
132+
}
133+
"schemas" => {
134+
// Extract schemas identifiers (e.g., [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA])
135+
metadata.schemas = extract_identifier_array(allocator, &prop.value);
136+
}
137+
"providers" => {
138+
// Extract providers as full OutputExpression
139+
// Handles complex expressions like [{provide: TOKEN, useFactory: Factory}]
140+
metadata.providers = convert_oxc_expression(allocator, &prop.value);
141+
}
142+
"viewProviders" => {
143+
// Extract view providers as full OutputExpression
144+
metadata.view_providers = convert_oxc_expression(allocator, &prop.value);
145+
}
127146
_ => {
128147
// Unknown property - ignore
129148
}
@@ -193,7 +212,6 @@ fn extract_boolean_value(expr: &Expression<'_>) -> Option<bool> {
193212
_ => None,
194213
}
195214
}
196-
197215
/// Extract an array of strings from an expression.
198216
fn extract_string_array<'a>(
199217
allocator: &'a Allocator,
@@ -293,6 +311,8 @@ fn extract_change_detection(expr: &Expression<'_>) -> ChangeDetectionStrategy {
293311
}
294312

295313
/// Extract host metadata from a host object expression.
314+
///
315+
/// Reference: packages/compiler/src/render3/view/compiler.ts:560-604
296316
fn extract_host_metadata<'a>(
297317
allocator: &'a Allocator,
298318
expr: &Expression<'a>,
@@ -305,6 +325,8 @@ fn extract_host_metadata<'a>(
305325
properties: Vec::new_in(allocator),
306326
attributes: Vec::new_in(allocator),
307327
listeners: Vec::new_in(allocator),
328+
class_attr: None,
329+
style_attr: None,
308330
};
309331

310332
for prop in &obj.properties {
@@ -325,8 +347,20 @@ fn extract_host_metadata<'a>(
325347
// Event listener: (click)
326348
host.listeners.push((key_name, value));
327349
} else {
328-
// Static attribute
329-
host.attributes.push((key_name, value));
350+
// Check for special attributes (class and style)
351+
// Reference: compiler.ts:567-588
352+
match key_str {
353+
"class" => {
354+
host.class_attr = Some(value);
355+
}
356+
"style" => {
357+
host.style_attr = Some(value);
358+
}
359+
_ => {
360+
// Regular static attribute
361+
host.attributes.push((key_name, value));
362+
}
363+
}
330364
}
331365
}
332366
}

crates/oxc_angular_compiler/src/component/definition.rs

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,29 @@ fn generate_cmp_definition<'a>(
418418
});
419419
}
420420

421+
// data: {animation: [...]} - animation triggers
422+
// See: packages/compiler/src/render3/view/compiler.ts:325-331
423+
if let Some(ref animations) = metadata.animations {
424+
// Create the inner map: {animation: animationsExpr}
425+
let mut data_entries: OxcVec<'a, LiteralMapEntry<'a>> =
426+
OxcVec::with_capacity_in(1, allocator);
427+
data_entries.push(LiteralMapEntry {
428+
key: Atom::from("animation"),
429+
// Use the full animations expression directly
430+
value: animations.clone_in(allocator),
431+
quoted: false,
432+
});
433+
434+
entries.push(LiteralMapEntry {
435+
key: Atom::from("data"),
436+
value: OutputExpression::LiteralMap(Box::new_in(
437+
LiteralMapExpr { entries: data_entries, source_span: None },
438+
allocator,
439+
)),
440+
quoted: false,
441+
});
442+
}
443+
421444
// Create the config object
422445
let config = OutputExpression::LiteralMap(Box::new_in(
423446
LiteralMapExpr { entries, source_span: None },
@@ -670,7 +693,7 @@ fn generate_features_array<'a>(
670693

671694
// 1. ProvidersFeature - when providers or viewProviders are defined
672695
// Format: ɵɵProvidersFeature([providers], [viewProviders]?)
673-
if !metadata.providers.is_empty() || !metadata.view_providers.is_empty() {
696+
if metadata.providers.is_some() || metadata.view_providers.is_some() {
674697
let providers_feature = generate_providers_feature(allocator, metadata);
675698
features.push(providers_feature);
676699
}
@@ -715,32 +738,33 @@ fn generate_features_array<'a>(
715738

716739
/// Generate `ɵɵProvidersFeature([providers], [viewProviders]?)` expression.
717740
///
718-
/// See: packages/compiler/src/render3/view/compiler.ts:129-137
741+
/// See: packages/compiler/src/render3/view/compiler.ts:119-135
719742
fn generate_providers_feature<'a>(
720743
allocator: &'a Allocator,
721744
metadata: &ComponentMetadata<'a>,
722745
) -> OutputExpression<'a> {
723746
let fn_expr = create_angular_fn_ref(allocator, Identifiers::PROVIDERS_FEATURE);
724747

725748
// Build args: [providers, viewProviders?]
726-
let has_view_providers = !metadata.view_providers.is_empty();
749+
let has_view_providers = metadata.view_providers.is_some();
727750
let capacity = if has_view_providers { 2 } else { 1 };
728751
let mut args: OxcVec<'a, OutputExpression<'a>> = OxcVec::with_capacity_in(capacity, allocator);
729752

730-
// First arg: providers array (or empty array if no providers)
731-
let providers_array = if metadata.providers.is_empty() {
732-
OutputExpression::LiteralArray(Box::new_in(
733-
LiteralArrayExpr { entries: OxcVec::new_in(allocator), source_span: None },
734-
allocator,
735-
))
736-
} else {
737-
create_providers_array(allocator, &metadata.providers)
738-
};
739-
args.push(providers_array);
753+
// First arg: providers expression (or empty array if no providers)
754+
let providers_expr = metadata.providers.as_ref().map_or_else(
755+
|| {
756+
OutputExpression::LiteralArray(Box::new_in(
757+
LiteralArrayExpr { entries: OxcVec::new_in(allocator), source_span: None },
758+
allocator,
759+
))
760+
},
761+
|p| p.clone_in(allocator),
762+
);
763+
args.push(providers_expr);
740764

741765
// Second arg: viewProviders (only if present)
742-
if has_view_providers {
743-
args.push(create_providers_array(allocator, &metadata.view_providers));
766+
if let Some(ref view_providers) = metadata.view_providers {
767+
args.push(view_providers.clone_in(allocator));
744768
}
745769

746770
OutputExpression::InvokeFunction(Box::new_in(
@@ -754,26 +778,6 @@ fn generate_providers_feature<'a>(
754778
))
755779
}
756780

757-
/// Create an array of provider references.
758-
fn create_providers_array<'a>(
759-
allocator: &'a Allocator,
760-
providers: &[Atom<'a>],
761-
) -> OutputExpression<'a> {
762-
let mut entries: OxcVec<'a, OutputExpression<'a>> =
763-
OxcVec::with_capacity_in(providers.len(), allocator);
764-
for provider in providers {
765-
// Provider is a reference to a class/token
766-
entries.push(OutputExpression::ReadVar(Box::new_in(
767-
ReadVarExpr { name: provider.clone(), source_span: None },
768-
allocator,
769-
)));
770-
}
771-
OutputExpression::LiteralArray(Box::new_in(
772-
LiteralArrayExpr { entries, source_span: None },
773-
allocator,
774-
))
775-
}
776-
777781
/// Generate `ɵɵHostDirectivesFeature([directives])` expression.
778782
///
779783
/// Handles both simple and complex host directive configurations:
@@ -1293,12 +1297,31 @@ mod tests {
12931297
assert!(result.is_none(), "Should return None when no features are needed");
12941298
}
12951299

1300+
/// Helper to create a providers array expression for tests.
1301+
fn create_test_providers_array<'a>(
1302+
allocator: &'a Allocator,
1303+
names: &[&'a str],
1304+
) -> OutputExpression<'a> {
1305+
let mut entries: OxcVec<'a, OutputExpression<'a>> =
1306+
OxcVec::with_capacity_in(names.len(), allocator);
1307+
for name in names {
1308+
entries.push(OutputExpression::ReadVar(Box::new_in(
1309+
ReadVarExpr { name: Atom::from(*name), source_span: None },
1310+
allocator,
1311+
)));
1312+
}
1313+
OutputExpression::LiteralArray(Box::new_in(
1314+
LiteralArrayExpr { entries, source_span: None },
1315+
allocator,
1316+
))
1317+
}
1318+
12961319
#[test]
12971320
fn test_providers_feature() {
12981321
let allocator = Allocator::default();
12991322
let mut metadata = create_test_metadata(&allocator);
1300-
metadata.providers.push(Atom::from("ServiceA"));
1301-
metadata.providers.push(Atom::from("ServiceB"));
1323+
metadata.providers =
1324+
Some(create_test_providers_array(&allocator, &["ServiceA", "ServiceB"]));
13021325

13031326
let result = generate_features_array(&allocator, &metadata).unwrap();
13041327

@@ -1314,8 +1337,8 @@ mod tests {
13141337
fn test_providers_with_view_providers() {
13151338
let allocator = Allocator::default();
13161339
let mut metadata = create_test_metadata(&allocator);
1317-
metadata.providers.push(Atom::from("ServiceA"));
1318-
metadata.view_providers.push(Atom::from("ViewService"));
1340+
metadata.providers = Some(create_test_providers_array(&allocator, &["ServiceA"]));
1341+
metadata.view_providers = Some(create_test_providers_array(&allocator, &["ViewService"]));
13191342

13201343
let result = generate_features_array(&allocator, &metadata).unwrap();
13211344

@@ -1332,7 +1355,7 @@ mod tests {
13321355
let allocator = Allocator::default();
13331356
let mut metadata = create_test_metadata(&allocator);
13341357
// Empty providers, but viewProviders present
1335-
metadata.view_providers.push(Atom::from("ViewService"));
1358+
metadata.view_providers = Some(create_test_providers_array(&allocator, &["ViewService"]));
13361359

13371360
let result = generate_features_array(&allocator, &metadata).unwrap();
13381361

@@ -1457,7 +1480,7 @@ mod tests {
14571480
fn test_multiple_features() {
14581481
let allocator = Allocator::default();
14591482
let mut metadata = create_test_metadata(&allocator);
1460-
metadata.providers.push(Atom::from("ServiceA"));
1483+
metadata.providers = Some(create_test_providers_array(&allocator, &["ServiceA"]));
14611484
metadata.uses_inheritance = true;
14621485
metadata.lifecycle = LifecycleMetadata { uses_on_changes: true };
14631486

@@ -1610,7 +1633,7 @@ mod tests {
16101633
fn test_feature_order() {
16111634
let allocator = Allocator::default();
16121635
let mut metadata = create_test_metadata(&allocator);
1613-
metadata.providers.push(Atom::from("ServiceA"));
1636+
metadata.providers = Some(create_test_providers_array(&allocator, &["ServiceA"]));
16141637
metadata.uses_inheritance = true;
16151638
metadata.lifecycle = LifecycleMetadata { uses_on_changes: true };
16161639
metadata.external_styles.push(Atom::from("./styles.css"));
@@ -1648,4 +1671,29 @@ mod tests {
16481671
"NgOnChangesFeature should come before ExternalStylesFeature"
16491672
);
16501673
}
1674+
1675+
// =========================================================================
1676+
// Animations Data Tests
1677+
// =========================================================================
1678+
1679+
#[test]
1680+
fn test_animations_data_field() {
1681+
let allocator = Allocator::default();
1682+
let mut metadata = create_test_metadata(&allocator);
1683+
// Create an animations expression (identifier reference)
1684+
metadata.animations = Some(OutputExpression::ReadVar(Box::new_in(
1685+
ReadVarExpr { name: Atom::from("myAnimations"), source_span: None },
1686+
&allocator,
1687+
)));
1688+
1689+
// We need a full compilation job to generate the definition
1690+
// For this test, we'll just verify the animations field is set
1691+
assert!(metadata.animations.is_some());
1692+
// Verify it's a ReadVar expression with the correct name
1693+
if let Some(OutputExpression::ReadVar(var)) = &metadata.animations {
1694+
assert_eq!(var.name.as_str(), "myAnimations");
1695+
} else {
1696+
panic!("Expected ReadVar expression for animations");
1697+
}
1698+
}
16511699
}

0 commit comments

Comments
 (0)