@@ -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,36 @@ impl Rule for RequirePostMessageTargetOrigin {
7982 }
8083}
8184
85+ fn is_message_port_expression ( expr : & Expression < ' _ > ) -> bool {
86+ let expr = expr. without_parentheses ( ) ;
87+
88+ if let Expression :: Identifier ( ident) = expr
89+ && matches ! ( ident. name. as_str( ) , "port" | "port1" | "port2" | "messagePort" )
90+ {
91+ return true ;
92+ }
93+
94+ let Some ( member_expr) = 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+ return true ;
100+ }
101+
102+ if member_expr. is_computed ( )
103+ && member_expr. object ( ) . without_parentheses ( ) . get_member_expr ( ) . is_some_and (
104+ |object_member| {
105+ object_member. static_property_name ( ) . is_some_and ( |name| name == "ports" )
106+ } ,
107+ )
108+ {
109+ return true ;
110+ }
111+
112+ is_message_port_expression ( member_expr. object ( ) )
113+ }
114+
82115#[ test]
83116fn test ( ) {
84117 use crate :: tester:: Tester ;
@@ -101,6 +134,10 @@ fn test() {
101134 "window.c.postMessage?.(message)" ,
102135 "window.a.b?.postMessage(message)" ,
103136 "window?.a?.b?.postMessage(message)" ,
137+ "event.ports[0].postMessage(message)" ,
138+ "channel.port1.postMessage(message)" ,
139+ "channel['port2'].postMessage(message)" ,
140+ "event?.ports[0].postMessage(message)" ,
104141 ] ;
105142
106143 let fail = vec ! [
0 commit comments