Skip to content
Merged
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
17 changes: 17 additions & 0 deletions crates/oxc_angular_compiler/src/component/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ impl AngularVersion {
self.major >= 20
}

/// Check if this version supports standalone `ɵɵinterpolate*` instructions (v20.0.0+).
///
/// Angular v20 introduced standalone `ɵɵinterpolate1`–`ɵɵinterpolateV` instructions
/// used as nested calls within `ɵɵproperty`/`ɵɵattribute`. Earlier versions use
/// combined `ɵɵpropertyInterpolate*`/`ɵɵattributeInterpolate*` instructions.
pub fn supports_value_interpolation(&self) -> bool {
self.major >= 20
}

/// Check if this version supports `ɵɵdomProperty` (v20.0.0+).
///
/// Angular v20 introduced `ɵɵdomProperty` for host/DomOnly property bindings.
/// Earlier versions use `ɵɵhostProperty` instead.
pub fn supports_dom_property(&self) -> bool {
self.major >= 20
}

/// Parse a version string like "19.0.0" or "19.0.0-rc.1".
///
/// Returns `None` if the version string is invalid.
Expand Down
20 changes: 15 additions & 5 deletions crates/oxc_angular_compiler/src/component/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use crate::pipeline::emit::{
};
use crate::pipeline::ingest::{
HostBindingInput, IngestOptions, ingest_component, ingest_component_with_options,
ingest_host_binding,
ingest_host_binding_with_version,
};
use crate::transform::HtmlToR3Transform;
use crate::transform::html_to_r3::TransformOptions as R3TransformOptions;
Expand Down Expand Up @@ -2423,8 +2423,12 @@ fn compile_component_full<'a>(
// Pass the template pool's current index to ensure host binding constants
// continue from where template compilation left off (avoiding duplicate names)
let template_pool_index = job.pool.next_name_index();
let host_binding_output =
compile_component_host_bindings(allocator, metadata, template_pool_index);
let host_binding_output = compile_component_host_bindings(
allocator,
metadata,
template_pool_index,
options.angular_version,
);

// Extract the result and update pool index if host bindings were compiled
let (host_binding_result, host_binding_next_pool_index, host_binding_declarations) =
Expand Down Expand Up @@ -2848,6 +2852,7 @@ pub fn compile_template_to_js_with_options<'a>(
component_name,
options.selector.as_deref(),
host_pool_starting_index,
options.angular_version,
) {
// Add host binding pool declarations (pure functions, etc.)
for decl in host_result.declarations {
Expand Down Expand Up @@ -3111,6 +3116,7 @@ fn compile_component_host_bindings<'a>(
allocator: &'a Allocator,
metadata: &ComponentMetadata<'a>,
pool_starting_index: u32,
angular_version: Option<AngularVersion>,
) -> Option<HostBindingCompilationOutput<'a>> {
let host = metadata.host.as_ref()?;

Expand All @@ -3134,7 +3140,8 @@ fn compile_component_host_bindings<'a>(

// Ingest and compile the host bindings with the pool starting index
// This ensures constant names continue from where template compilation left off
let mut job = ingest_host_binding(allocator, input, pool_starting_index);
let mut job =
ingest_host_binding_with_version(allocator, input, pool_starting_index, angular_version);
let result = compile_host_bindings(&mut job);

// Get the next pool index after host binding compilation
Expand Down Expand Up @@ -3411,6 +3418,7 @@ fn compile_host_bindings_from_input<'a>(
component_name: &str,
selector: Option<&str>,
pool_starting_index: u32,
angular_version: Option<crate::AngularVersion>,
) -> Option<HostBindingCompilationResult<'a>> {
use oxc_allocator::FromIn;

Expand All @@ -3436,7 +3444,8 @@ fn compile_host_bindings_from_input<'a>(
// Convert to HostBindingInput and compile
let input =
convert_host_metadata_to_input(allocator, &host, component_name_atom, component_selector);
let mut job = ingest_host_binding(allocator, input, pool_starting_index);
let mut job =
ingest_host_binding_with_version(allocator, input, pool_starting_index, angular_version);
let result = compile_host_bindings(&mut job);

Some(result)
Expand Down Expand Up @@ -3471,6 +3480,7 @@ pub fn compile_host_bindings_for_linker(
component_name,
selector,
pool_starting_index,
None, // Linker always targets latest Angular version
)?;

let emitter = JsEmitter::new();
Expand Down
30 changes: 30 additions & 0 deletions crates/oxc_angular_compiler/src/pipeline/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,23 @@ impl<'a> ComponentCompilationJob<'a> {
self.angular_version.map_or(true, |v: AngularVersion| v.supports_conditional_create())
}

/// Check if standalone `ɵɵinterpolate*` instructions are supported (Angular 20+).
///
/// Returns `true` for Angular 20+ or when version is unknown (None = latest).
/// Returns `false` for Angular 19 and earlier, which use combined
/// `ɵɵpropertyInterpolate*`/`ɵɵattributeInterpolate*` instructions.
pub fn supports_value_interpolation(&self) -> bool {
self.angular_version.map_or(true, |v: AngularVersion| v.supports_value_interpolation())
}

/// Check if `ɵɵdomProperty` is supported (Angular 20+).
///
/// Returns `true` for Angular 20+ or when version is unknown (None = latest).
/// Returns `false` for Angular 19 and earlier, which use `ɵɵhostProperty` instead.
pub fn supports_dom_property(&self) -> bool {
self.angular_version.map_or(true, |v: AngularVersion| v.supports_dom_property())
}

/// Allocates a new cross-reference ID.
pub fn allocate_xref_id(&mut self) -> XrefId {
let id = XrefId::new(self.next_xref_id);
Expand Down Expand Up @@ -601,6 +618,8 @@ pub struct HostBindingCompilationJob<'a> {
pub fn_suffix: Atom<'a>,
/// Diagnostics collected during compilation.
pub diagnostics: std::vec::Vec<OxcDiagnostic>,
/// Angular version for version-gated instruction emission.
pub angular_version: Option<AngularVersion>,
}

impl<'a> HostBindingCompilationJob<'a> {
Expand Down Expand Up @@ -646,6 +665,7 @@ impl<'a> HostBindingCompilationJob<'a> {
mode: TemplateCompilationMode::DomOnly, // Host bindings always use DomOnly
fn_suffix: Atom::from("HostBindings"),
diagnostics: std::vec::Vec::new(),
angular_version: None,
}
}

Expand All @@ -654,6 +674,16 @@ impl<'a> HostBindingCompilationJob<'a> {
CompilationJobKind::Host
}

/// Check if standalone `ɵɵinterpolate*` instructions are supported (Angular 20+).
pub fn supports_value_interpolation(&self) -> bool {
self.angular_version.map_or(true, |v| v.supports_value_interpolation())
}

/// Check if `ɵɵdomProperty` is supported (Angular 20+).
pub fn supports_dom_property(&self) -> bool {
self.angular_version.map_or(true, |v| v.supports_dom_property())
}

/// Allocates a new cross-reference ID.
pub fn allocate_xref_id(&mut self) -> XrefId {
let id = XrefId::new(self.next_xref_id);
Expand Down
11 changes: 11 additions & 0 deletions crates/oxc_angular_compiler/src/pipeline/ingest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3941,13 +3941,24 @@ pub fn ingest_host_binding<'a>(
allocator: &'a Allocator,
input: HostBindingInput<'a>,
pool_starting_index: u32,
) -> HostBindingCompilationJob<'a> {
ingest_host_binding_with_version(allocator, input, pool_starting_index, None)
}

/// Ingest host bindings into a `HostBindingCompilationJob` with a specific Angular version.
pub fn ingest_host_binding_with_version<'a>(
allocator: &'a Allocator,
input: HostBindingInput<'a>,
pool_starting_index: u32,
angular_version: Option<crate::AngularVersion>,
) -> HostBindingCompilationJob<'a> {
let mut job = HostBindingCompilationJob::with_pool_starting_index(
allocator,
input.component_name,
input.component_selector,
pool_starting_index,
);
job.angular_version = angular_version;

// Ingest host properties
for property in input.properties {
Expand Down
Loading
Loading