Skip to content

Commit 85d7d62

Browse files
committed
save
1 parent 58d316b commit 85d7d62

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+3208
-201
lines changed

crates/oxc_angular_compiler/src/ast/expression.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,68 @@ pub enum BindingType {
797797
/// An animation binding.
798798
Animation,
799799
}
800+
801+
// ============================================================================
802+
// Parsed properties and events (for host bindings)
803+
// ============================================================================
804+
805+
/// A parsed property binding from a component or directive.
806+
///
807+
/// This is used for host bindings in `@HostBinding()` decorators.
808+
/// Ported from Angular's `expression_parser/ast.ts` ParsedProperty.
809+
#[derive(Debug)]
810+
pub struct ParsedProperty<'a> {
811+
/// The property name.
812+
pub name: Atom<'a>,
813+
/// The binding expression.
814+
pub expression: ASTWithSource<'a>,
815+
/// The type of property binding.
816+
pub property_type: ParsedPropertyType,
817+
/// The source span of the binding.
818+
pub source_span: oxc_span::Span,
819+
/// The span of the property name.
820+
pub key_span: oxc_span::Span,
821+
/// The span of the value expression (if present).
822+
pub value_span: Option<oxc_span::Span>,
823+
}
824+
825+
impl<'a> ParsedProperty<'a> {
826+
/// Returns true if this is a literal attribute binding.
827+
pub fn is_literal(&self) -> bool {
828+
self.property_type == ParsedPropertyType::LiteralAttr
829+
}
830+
831+
/// Returns true if this is a legacy animation binding.
832+
pub fn is_legacy_animation(&self) -> bool {
833+
self.property_type == ParsedPropertyType::LegacyAnimation
834+
}
835+
836+
/// Returns true if this is an animation binding.
837+
pub fn is_animation(&self) -> bool {
838+
self.property_type == ParsedPropertyType::Animation
839+
}
840+
}
841+
842+
/// A parsed event binding from a component or directive.
843+
///
844+
/// This is used for host listeners in `@HostListener()` decorators.
845+
/// Ported from Angular's `expression_parser/ast.ts` ParsedEvent.
846+
#[derive(Debug)]
847+
pub struct ParsedEvent<'a> {
848+
/// The event name.
849+
pub name: Atom<'a>,
850+
/// The event target or animation phase.
851+
/// For regular events: "window", "document", "body", or None.
852+
/// For legacy animation events: the animation phase.
853+
pub target_or_phase: Option<Atom<'a>>,
854+
/// The type of event binding.
855+
pub event_type: ParsedEventType,
856+
/// The handler expression.
857+
pub handler: ASTWithSource<'a>,
858+
/// The source span of the binding.
859+
pub source_span: oxc_span::Span,
860+
/// The span of the handler expression.
861+
pub handler_span: oxc_span::Span,
862+
/// The span of the event name.
863+
pub key_span: oxc_span::Span,
864+
}

crates/oxc_angular_compiler/src/ast/r3.rs

Lines changed: 152 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,159 @@
55
//!
66
//! Ported from Angular's `render3/r3_ast.ts`.
77
8-
use oxc_allocator::{Box, Vec};
8+
use oxc_allocator::{Box, HashMap, Vec};
99
use oxc_span::{Atom, Span};
10-
use rustc_hash::FxHashMap;
1110

1211
use crate::ast::expression::{ASTWithSource, AngularExpression, BindingType, ParsedEventType};
12+
use crate::i18n::ast::IcuType;
13+
14+
// ============================================================================
15+
// i18n Metadata
16+
// ============================================================================
17+
18+
/// i18n metadata attached to R3 nodes.
19+
#[derive(Debug)]
20+
pub enum I18nMeta<'a> {
21+
/// Root of an i18n message.
22+
Message(I18nMessage<'a>),
23+
/// Part of a containing message.
24+
Node(I18nNode<'a>),
25+
}
26+
27+
/// An i18n message containing translatable content.
28+
#[derive(Debug)]
29+
pub struct I18nMessage<'a> {
30+
/// Message AST nodes.
31+
pub nodes: Vec<'a, I18nNode<'a>>,
32+
/// The meaning of the message (for disambiguation).
33+
pub meaning: Atom<'a>,
34+
/// Description of the message for translators.
35+
pub description: Atom<'a>,
36+
/// Custom ID specified by the developer.
37+
pub custom_id: Atom<'a>,
38+
/// The computed message ID.
39+
pub id: Atom<'a>,
40+
/// Legacy IDs for backwards compatibility.
41+
pub legacy_ids: Vec<'a, Atom<'a>>,
42+
}
43+
44+
/// i18n AST node.
45+
#[derive(Debug)]
46+
pub enum I18nNode<'a> {
47+
/// Plain text content.
48+
Text(I18nText<'a>),
49+
/// Container for child nodes.
50+
Container(I18nContainer<'a>),
51+
/// ICU expression (plural, select, selectordinal).
52+
Icu(I18nIcu<'a>),
53+
/// HTML tag placeholder.
54+
TagPlaceholder(I18nTagPlaceholder<'a>),
55+
/// Expression placeholder.
56+
Placeholder(I18nPlaceholder<'a>),
57+
/// ICU placeholder (nested ICU reference).
58+
IcuPlaceholder(I18nIcuPlaceholder<'a>),
59+
/// Control flow block placeholder.
60+
BlockPlaceholder(I18nBlockPlaceholder<'a>),
61+
}
62+
63+
/// Plain text content.
64+
#[derive(Debug)]
65+
pub struct I18nText<'a> {
66+
/// The text value.
67+
pub value: Atom<'a>,
68+
/// Source span.
69+
pub source_span: Span,
70+
}
71+
72+
/// Container for child nodes.
73+
#[derive(Debug)]
74+
pub struct I18nContainer<'a> {
75+
/// Child nodes.
76+
pub children: Vec<'a, I18nNode<'a>>,
77+
/// Source span.
78+
pub source_span: Span,
79+
}
80+
81+
/// ICU expression (plural, select, selectordinal).
82+
#[derive(Debug)]
83+
pub struct I18nIcu<'a> {
84+
/// The expression being evaluated.
85+
pub expression: Atom<'a>,
86+
/// ICU type (plural, select, selectordinal).
87+
pub icu_type: IcuType,
88+
/// Case branches.
89+
pub cases: HashMap<'a, Atom<'a>, I18nNode<'a>>,
90+
/// Source span.
91+
pub source_span: Span,
92+
/// Expression placeholder name (for message serialization).
93+
pub expression_placeholder: Option<Atom<'a>>,
94+
}
95+
96+
/// HTML tag placeholder.
97+
#[derive(Debug)]
98+
pub struct I18nTagPlaceholder<'a> {
99+
/// Tag name.
100+
pub tag: Atom<'a>,
101+
/// Tag attributes.
102+
pub attrs: HashMap<'a, Atom<'a>, Atom<'a>>,
103+
/// Start tag placeholder name.
104+
pub start_name: Atom<'a>,
105+
/// Close tag placeholder name.
106+
pub close_name: Atom<'a>,
107+
/// Child nodes.
108+
pub children: Vec<'a, I18nNode<'a>>,
109+
/// Whether this is a void element.
110+
pub is_void: bool,
111+
/// Source span (overall).
112+
pub source_span: Span,
113+
/// Start tag source span.
114+
pub start_source_span: Option<Span>,
115+
/// End tag source span.
116+
pub end_source_span: Option<Span>,
117+
}
118+
119+
/// Expression placeholder.
120+
#[derive(Debug)]
121+
pub struct I18nPlaceholder<'a> {
122+
/// The expression value.
123+
pub value: Atom<'a>,
124+
/// Placeholder name.
125+
pub name: Atom<'a>,
126+
/// Source span.
127+
pub source_span: Span,
128+
}
129+
130+
/// ICU placeholder (reference to a nested ICU).
131+
#[derive(Debug)]
132+
pub struct I18nIcuPlaceholder<'a> {
133+
/// The ICU expression.
134+
pub value: Box<'a, I18nIcu<'a>>,
135+
/// Placeholder name.
136+
pub name: Atom<'a>,
137+
/// Source span.
138+
pub source_span: Span,
139+
}
140+
141+
/// Control flow block placeholder.
142+
#[derive(Debug)]
143+
pub struct I18nBlockPlaceholder<'a> {
144+
/// Block name.
145+
pub name: Atom<'a>,
146+
/// Block parameters.
147+
pub parameters: Vec<'a, Atom<'a>>,
148+
/// Start block placeholder name.
149+
pub start_name: Atom<'a>,
150+
/// End block placeholder name.
151+
pub close_name: Atom<'a>,
152+
/// Child nodes.
153+
pub children: Vec<'a, I18nNode<'a>>,
154+
/// Source span (overall).
155+
pub source_span: Span,
156+
/// Start block source span.
157+
pub start_source_span: Option<Span>,
158+
/// End block source span.
159+
pub end_source_span: Option<Span>,
160+
}
13161

14162
// ============================================================================
15163
// Core Node Enum
@@ -873,9 +1021,9 @@ pub struct R3Directive<'a> {
8731021
#[derive(Debug)]
8741022
pub struct R3Icu<'a> {
8751023
/// Variable expressions.
876-
pub vars: FxHashMap<Atom<'a>, R3BoundText<'a>>,
1024+
pub vars: HashMap<'a, Atom<'a>, R3BoundText<'a>>,
8771025
/// Placeholder expressions.
878-
pub placeholders: FxHashMap<Atom<'a>, R3IcuPlaceholder<'a>>,
1026+
pub placeholders: HashMap<'a, Atom<'a>, R3IcuPlaceholder<'a>>,
8791027
/// Source span.
8801028
pub source_span: Span,
8811029
/// i18n metadata.
@@ -891,25 +1039,6 @@ pub enum R3IcuPlaceholder<'a> {
8911039
BoundText(R3BoundText<'a>),
8921040
}
8931041

894-
// ============================================================================
895-
// i18n
896-
// ============================================================================
897-
898-
/// i18n metadata for internationalization.
899-
#[derive(Debug)]
900-
pub struct I18nMeta<'a> {
901-
/// Message ID.
902-
pub id: Option<Atom<'a>>,
903-
/// Custom ID.
904-
pub custom_id: Option<Atom<'a>>,
905-
/// Legacy ID list.
906-
pub legacy_ids: Vec<'a, Atom<'a>>,
907-
/// Description.
908-
pub description: Option<Atom<'a>>,
909-
/// Meaning.
910-
pub meaning: Option<Atom<'a>>,
911-
}
912-
9131042
// ============================================================================
9141043
// Visitor
9151044
// ============================================================================

crates/oxc_angular_compiler/src/i18n/ast.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ pub struct TagPlaceholder {
266266

267267
impl TagPlaceholder {
268268
/// Creates a new tag placeholder.
269-
#[allow(clippy::too_many_arguments)]
269+
#[expect(clippy::too_many_arguments)]
270270
pub fn new(
271271
tag: String,
272272
attrs: FxHashMap<String, String>,
@@ -353,7 +353,7 @@ pub struct BlockPlaceholder {
353353

354354
impl BlockPlaceholder {
355355
/// Creates a new block placeholder.
356-
#[allow(clippy::too_many_arguments)]
356+
#[expect(clippy::too_many_arguments)]
357357
pub fn new(
358358
name: String,
359359
parameters: Vec<String>,
@@ -587,7 +587,11 @@ impl Visitor for CloneVisitor {
587587
if let Node::Icu(icu) = icu_node {
588588
Node::IcuPlaceholder(IcuPlaceholder::new(icu, ph.name.clone(), ph.source_span))
589589
} else {
590-
unreachable!()
590+
// visit_icu should always return Node::Icu by design.
591+
// This is a compiler bug if we reach here.
592+
debug_assert!(false, "visit_icu should return Node::Icu");
593+
// Return the original placeholder unchanged as fallback
594+
Node::IcuPlaceholder(ph.clone())
591595
}
592596
}
593597

crates/oxc_angular_compiler/src/i18n/digest.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ impl Visitor for SerializerIgnoreIcuExpVisitor {
239239
///
240240
/// WARNING: This function has not been designed or tested with security in mind.
241241
/// DO NOT USE IT IN A SECURITY SENSITIVE CONTEXT.
242+
#[expect(clippy::many_single_char_names, clippy::unreadable_literal)]
242243
pub fn sha1(str: &str) -> String {
243244
let utf8 = str.as_bytes();
244245
let words32 = bytes_to_words32(utf8, Endian::Big);
@@ -306,6 +307,7 @@ fn to_hex_u32(value: u32) -> String {
306307
format!("{:08x}", value)
307308
}
308309

310+
#[expect(clippy::unreadable_literal)]
309311
fn fk(index: usize, b: u32, c: u32, d: u32) -> (u32, u32) {
310312
if index < 20 {
311313
((b & c) | (!b & d), 0x5a827999)
@@ -332,11 +334,15 @@ pub fn fingerprint(str: &str) -> u64 {
332334
let utf8 = str.as_bytes();
333335

334336
let mut hi = hash32(utf8, 0);
337+
#[expect(clippy::unreadable_literal)]
335338
let mut lo = hash32(utf8, 102072);
336339

337340
if hi == 0 && (lo == 0 || lo == 1) {
338-
hi ^= 0x130f9bef;
339-
lo ^= 0x94a0a928u32; // -0x6b5f56d8 as u32 (two's complement)
341+
#[expect(clippy::unreadable_literal)]
342+
{
343+
hi ^= 0x130f9bef;
344+
lo ^= 0x94a0a928u32; // -0x6b5f56d8 as u32 (two's complement)
345+
}
340346
}
341347

342348
((hi as u64) << 32) | (lo as u64)
@@ -353,9 +359,11 @@ pub fn compute_msg_id(msg: &str, meaning: &str) -> String {
353359
}
354360

355361
// Return lower 63 bits as decimal string
362+
#[expect(clippy::unreadable_literal)]
356363
(msg_fingerprint & 0x7FFFFFFFFFFFFFFF).to_string()
357364
}
358365

366+
#[expect(clippy::unreadable_literal)]
359367
fn hash32(bytes: &[u8], mut c: u32) -> u32 {
360368
let mut a: u32 = 0x9e3779b9;
361369
let mut b: u32 = 0x9e3779b9;

0 commit comments

Comments
 (0)