@@ -3873,12 +3873,10 @@ fn test_let_declaration_with_multiple_context_refs_variable_naming() {
38733873// Const reference index: i18n property binding extraction
38743874// ============================================================================
38753875
3876- /// Tests that property bindings with i18n markers are extracted as BindingKind::Property
3877- /// in the consts array. Angular's attribute_extraction.ts has a condition
3878- /// `op.i18nMessage !== null && op.templateKind === null` that would produce I18n kind,
3879- /// but empirically Angular never produces I18n marker (6) in consts arrays across all
3880- /// tested components. The i18n metadata is handled by the i18n pipeline separately.
3881- /// The property binding should use Bindings marker (3) for directive matching.
3876+ /// Tests that pure property bindings with i18n markers are extracted as BindingKind::Property.
3877+ /// Pure property bindings like [heading]="title" i18n-heading keep Bindings marker (3) because
3878+ /// the runtime uses domProperty to set the value, not i18nAttributes. The I18n marker (6) is
3879+ /// only used for interpolated attributes that go through the i18n pipeline.
38823880#[ test]
38833881fn test_i18n_property_binding_extracted_as_property_kind ( ) {
38843882 let allocator = Allocator :: default ( ) ;
@@ -3903,26 +3901,22 @@ export class TestComponent {
39033901 None ,
39043902 ) ;
39053903
3906- // The consts array should contain [3,"heading"] (AttributeMarker.Bindings = 3)
3907- // Angular never produces [6,"heading"] (AttributeMarker.I18n = 6) in consts arrays .
3904+ // Pure property bindings keep Bindings marker (3), NOT I18n marker (6).
3905+ // The i18n marker on a property binding is a no-op for directive matching .
39083906 assert ! (
39093907 result. code. contains( r#"3,"heading""# ) ,
3910- "Property binding with i18n marker should produce Bindings AttributeMarker (3), not I18n (6). Output:\n {}" ,
3911- result. code
3912- ) ;
3913- assert ! (
3914- !result. code. contains( r#"6,"heading""# ) ,
3915- "Property binding with i18n marker should NOT produce I18n AttributeMarker (6). Output:\n {}" ,
3908+ "Pure property binding with i18n marker should produce Bindings AttributeMarker (3). Output:\n {}" ,
39163909 result. code
39173910 ) ;
39183911}
39193912
39203913/// Tests that interpolated attributes with i18n markers (e.g., heading="{{ name }}" i18n-heading)
3921- /// are extracted as BindingKind::Property (Bindings marker 3), not I18n marker 6.
3922- /// Angular's compiler never produces I18n AttributeMarker (6) in consts arrays.
3914+ /// are extracted as BindingKind::I18n (marker 6).
3915+ /// Angular's attribute_extraction.ts checks `op.i18nMessage !== null && op.templateKind === null`
3916+ /// and overrides the binding kind to I18n.
39233917/// This matches the real-world pattern in ClickUp's old-join-team component.
39243918#[ test]
3925- fn test_i18n_interpolated_attribute_extracted_as_property_kind ( ) {
3919+ fn test_i18n_interpolated_attribute_extracted_as_i18n_kind ( ) {
39263920 let allocator = Allocator :: default ( ) ;
39273921 let source = r#"
39283922import { Component } from '@angular/core';
@@ -3945,17 +3939,70 @@ export class TestComponent {
39453939 None ,
39463940 ) ;
39473941
3948- // The consts array should contain [3,"heading"] (AttributeMarker.Bindings = 3)
3949- // not [6,"heading"] (AttributeMarker.I18n = 6)
3950- // Angular's compiler never produces I18n marker in consts arrays.
3942+ // The consts array should contain [6,"heading"] (AttributeMarker.I18n = 6)
3943+ // because the interpolated attribute has an i18n message (i18n-heading).
39513944 assert ! (
3952- result. code. contains( r#"3,"heading""# ) ,
3953- "Interpolated attribute with i18n marker should produce Bindings AttributeMarker (3), not I18n (6). Output:\n {}" ,
3945+ result. code. contains( r#"6,"heading""# ) ,
3946+ "Interpolated attribute with i18n marker should produce I18n AttributeMarker (6). Output:\n {}" ,
3947+ result. code
3948+ ) ;
3949+ assert ! (
3950+ !result. code. contains( r#"3,"heading""# ) ,
3951+ "Interpolated attribute with i18n marker should NOT produce Bindings AttributeMarker (3). Output:\n {}" ,
3952+ result. code
3953+ ) ;
3954+ }
3955+
3956+ /// Tests that i18n property bindings in control flow don't produce extra consts entries.
3957+ /// When a property binding has i18n-attr (e.g., [cuTooltip]="expr" i18n-cuTooltip),
3958+ /// the consts entry should use Bindings marker (3), matching the conditional insertion point.
3959+ /// This ensures the entries deduplicate and don't shift downstream consts indices.
3960+ #[ test]
3961+ fn test_i18n_property_binding_in_control_flow_no_extra_consts ( ) {
3962+ let allocator = Allocator :: default ( ) ;
3963+ let source = r#"
3964+ import { Component } from '@angular/core';
3965+
3966+ @Component({
3967+ selector: 'test-comp',
3968+ template: `
3969+ <div data-test="body" class="body">
3970+ @if (showTooltip) {
3971+ <div data-test="inner"
3972+ [cuTooltip]="someExpr"
3973+ i18n-cuTooltip="@@copy-id">
3974+ Content
3975+ </div>
3976+ }
3977+ </div>
3978+ `,
3979+ standalone: true,
3980+ })
3981+ export class TestComponent {
3982+ someExpr = 'hello';
3983+ showTooltip = true;
3984+ }
3985+ "# ;
3986+
3987+ let result = transform_angular_file (
3988+ & allocator,
3989+ "test.component.ts" ,
3990+ source,
3991+ & ComponentTransformOptions :: default ( ) ,
3992+ None ,
3993+ ) ;
3994+
3995+ // The consts array should NOT contain [6,"cuTooltip"] because [cuTooltip]="expr"
3996+ // is a pure property binding, not an interpolated attribute.
3997+ assert ! (
3998+ !result. code. contains( r#"6,"cuTooltip""# ) ,
3999+ "Pure property binding in control flow should NOT produce I18n AttributeMarker (6). Output:\n {}" ,
39544000 result. code
39554001 ) ;
4002+ // Should use Bindings marker (3) instead
39564003 assert ! (
3957- ! result. code. contains( r#"6,"heading ""# ) ,
3958- "Interpolated attribute with i18n marker should NOT produce I18n AttributeMarker (6 ). Output:\n {}" ,
4004+ result. code. contains( r#"3,"cuTooltip ""# ) ,
4005+ "Pure property binding in control flow should produce Bindings AttributeMarker (3 ). Output:\n {}" ,
39594006 result. code
39604007 ) ;
39614008}
0 commit comments