@@ -62,6 +62,9 @@ impl Rule for RequirePostMessageTargetOrigin {
6262 _ => return ,
6363 } ;
6464 if matches ! ( member_expr. static_property_name( ) , Some ( name) if name == "postMessage" ) {
65+ if is_message_port_expression ( member_expr. object ( ) ) {
66+ return ;
67+ }
6568 let span = call_expr. arguments [ 0 ] . span ( ) ;
6669 ctx. diagnostic_with_suggestion (
6770 require_post_message_target_origin_diagnostic ( Span :: new ( span. end , span. end ) ) ,
@@ -79,6 +82,38 @@ impl Rule for RequirePostMessageTargetOrigin {
7982 }
8083}
8184
85+ fn is_message_port_expression ( expr : & Expression < ' _ > ) -> bool {
86+ let mut current_expr = expr. without_parentheses ( ) ;
87+ loop {
88+ if let Expression :: Identifier ( ident) = current_expr
89+ && matches ! ( ident. name. as_str( ) , "port" | "port1" | "port2" | "messagePort" )
90+ {
91+ return true ;
92+ }
93+
94+ let Some ( member_expr) = current_expr. get_member_expr ( ) else {
95+ return false ;
96+ } ;
97+
98+ if member_expr. static_property_name ( ) . is_some_and ( |name| matches ! ( name, "port1" | "port2" ) )
99+ {
100+ return true ;
101+ }
102+
103+ if member_expr. is_computed ( )
104+ && member_expr. object ( ) . without_parentheses ( ) . get_member_expr ( ) . is_some_and (
105+ |object_member| {
106+ object_member. static_property_name ( ) . is_some_and ( |name| name == "ports" )
107+ } ,
108+ )
109+ {
110+ return true ;
111+ }
112+
113+ current_expr = member_expr. object ( ) . without_parentheses ( ) ;
114+ }
115+ }
116+
82117#[ test]
83118fn test ( ) {
84119 use crate :: tester:: Tester ;
@@ -101,6 +136,10 @@ fn test() {
101136 "window.c.postMessage?.(message)" ,
102137 "window.a.b?.postMessage(message)" ,
103138 "window?.a?.b?.postMessage(message)" ,
139+ "event.ports[0].postMessage(message)" ,
140+ "channel.port1.postMessage(message)" ,
141+ "channel['port2'].postMessage(message)" ,
142+ "event?.ports[0].postMessage(message)" ,
104143 ] ;
105144
106145 let fail = vec ! [
0 commit comments