11use crate :: Declaration ;
2+ use crate :: DeclarationDef ;
3+ use crate :: class:: ClassDef ;
24use crate :: class:: ClassMethodDef ;
35use crate :: class:: ClassPropertyDef ;
46use crate :: diff:: ConstructorDiff ;
@@ -12,15 +14,71 @@ use crate::html::parameters::render_params;
1214use crate :: html:: render_context:: RenderContext ;
1315use crate :: html:: types:: render_type_def_colon;
1416use crate :: html:: util:: * ;
17+ use crate :: interface:: InterfaceDef ;
1518use crate :: js_doc:: JsDocTag ;
19+ use crate :: ts_type:: TsTypeDefKind ;
1620use deno_ast:: swc:: ast:: Accessibility ;
1721use deno_ast:: swc:: ast:: MethodKind ;
1822use indexmap:: IndexMap ;
1923use serde:: Deserialize ;
2024use serde:: Serialize ;
2125use std:: collections:: BTreeMap ;
26+ use std:: collections:: HashMap ;
2227use std:: collections:: HashSet ;
2328
29+ /// Collects method and property documentation from all interfaces
30+ /// implemented by a class, to be used as fallback when the class
31+ /// member lacks its own documentation.
32+ fn collect_inherited_docs (
33+ ctx : & RenderContext ,
34+ class_def : & ClassDef ,
35+ ) -> HashMap < String , String > {
36+ let mut inherited = HashMap :: new ( ) ;
37+
38+ for implement in class_def. implements . iter ( ) {
39+ let interface_name = match & implement. kind {
40+ TsTypeDefKind :: TypeRef ( type_ref) => & type_ref. type_name ,
41+ _ => continue ,
42+ } ;
43+
44+ // Search all doc nodes for a matching interface
45+ for nodes in ctx. ctx . doc_nodes . values ( ) {
46+ for node in nodes {
47+ if node. get_name ( ) != interface_name {
48+ continue ;
49+ }
50+ for decl in & node. declarations {
51+ if let DeclarationDef :: Interface ( iface) = & decl. def {
52+ collect_docs_from_interface ( & mut inherited, iface) ;
53+ }
54+ }
55+ }
56+ }
57+ }
58+
59+ inherited
60+ }
61+
62+ fn collect_docs_from_interface (
63+ inherited : & mut HashMap < String , String > ,
64+ iface : & InterfaceDef ,
65+ ) {
66+ for method in & iface. methods {
67+ if let Some ( doc) = & method. js_doc . doc {
68+ inherited
69+ . entry ( method. name . clone ( ) )
70+ . or_insert_with ( || doc. to_string ( ) ) ;
71+ }
72+ }
73+ for property in & iface. properties {
74+ if let Some ( doc) = & property. js_doc . doc {
75+ inherited
76+ . entry ( property. name . clone ( ) )
77+ . or_insert_with ( || doc. to_string ( ) ) ;
78+ }
79+ }
80+ }
81+
2482pub ( crate ) fn render_class (
2583 ctx : & RenderContext ,
2684 symbol : & DocNodeWithContext ,
@@ -47,6 +105,8 @@ pub(crate) fn render_class(
47105 . and_then ( |d| d. as_class ( ) )
48106 } ) ;
49107
108+ let inherited_docs = collect_inherited_docs ( ctx, class_def) ;
109+
50110 let class_items = partition_class_items (
51111 class_def. properties . clone ( ) ,
52112 class_def. methods . clone ( ) ,
@@ -89,6 +149,7 @@ pub(crate) fn render_class(
89149 class_items. static_properties ,
90150 class_items. static_property_changes . as_ref ( ) ,
91151 class_items. static_method_changes . as_ref ( ) ,
152+ & inherited_docs,
92153 ) ;
93154
94155 if !static_properties. is_empty ( ) {
@@ -104,6 +165,7 @@ pub(crate) fn render_class(
104165 name,
105166 class_items. static_methods ,
106167 class_items. static_method_changes . as_ref ( ) ,
168+ & inherited_docs,
107169 ) ;
108170
109171 if !static_methods. is_empty ( ) {
@@ -120,6 +182,7 @@ pub(crate) fn render_class(
120182 class_items. properties ,
121183 class_items. property_changes . as_ref ( ) ,
122184 class_items. method_changes . as_ref ( ) ,
185+ & inherited_docs,
123186 ) ;
124187
125188 if !properties. is_empty ( ) {
@@ -135,6 +198,7 @@ pub(crate) fn render_class(
135198 name,
136199 class_items. methods ,
137200 class_items. method_changes . as_ref ( ) ,
201+ & inherited_docs,
138202 ) ;
139203
140204 if !methods. is_empty ( ) {
@@ -585,6 +649,7 @@ fn render_class_accessor(
585649 getter : Option < & ClassMethodDef > ,
586650 setter : Option < & ClassMethodDef > ,
587651 method_changes : Option < & MethodsDiff > ,
652+ inherited_docs : & HashMap < String , String > ,
588653) -> DocEntryCtx {
589654 let getter_or_setter = getter. or ( setter) . unwrap ( ) ;
590655
@@ -605,7 +670,11 @@ fn render_class_accessor(
605670 } )
606671 } )
607672 . map_or_else ( String :: new, |ts_type| render_type_def_colon ( ctx, ts_type) ) ;
608- let js_doc = getter_or_setter. js_doc . doc . as_deref ( ) ;
673+ let js_doc = getter_or_setter
674+ . js_doc
675+ . doc
676+ . as_deref ( )
677+ . or_else ( || inherited_docs. get ( & * * name) . map ( |s| s. as_str ( ) ) ) ;
609678
610679 let mut tags = Tag :: from_js_doc ( & getter_or_setter. js_doc ) ;
611680 if let Some ( tag) = Tag :: from_accessibility ( getter_or_setter. accessibility ) {
@@ -689,6 +758,7 @@ fn render_class_method(
689758 method : & ClassMethodDef ,
690759 i : usize ,
691760 method_changes : Option < & MethodsDiff > ,
761+ inherited_docs : & HashMap < String , String > ,
692762) -> Option < DocEntryCtx > {
693763 if method. function_def . has_body && i != 0 {
694764 return None ;
@@ -750,6 +820,12 @@ fn render_class_method(
750820 ( None , None , None )
751821 } ;
752822
823+ let doc = method
824+ . js_doc
825+ . doc
826+ . as_deref ( )
827+ . or_else ( || inherited_docs. get ( & * method. name ) . map ( |s| s. as_str ( ) ) ) ;
828+
753829 Some ( DocEntryCtx :: new (
754830 ctx,
755831 id,
@@ -766,7 +842,7 @@ fn render_class_method(
766842 & method. function_def . return_type ,
767843 ) ,
768844 tags,
769- method . js_doc . doc . as_deref ( ) ,
845+ doc,
770846 & method. location ,
771847 diff_status,
772848 old_content,
@@ -780,6 +856,7 @@ fn render_class_property(
780856 class_name : & str ,
781857 property : & ClassPropertyDef ,
782858 property_changes : Option < & PropertiesDiff > ,
859+ inherited_docs : & HashMap < String , String > ,
783860) -> DocEntryCtx {
784861 let id = IdBuilder :: new ( ctx)
785862 . kind ( IdKind :: Property )
@@ -835,6 +912,12 @@ fn render_class_property(
835912 ( None , None , None )
836913 } ;
837914
915+ let doc = property
916+ . js_doc
917+ . doc
918+ . as_deref ( )
919+ . or_else ( || inherited_docs. get ( & * property. name ) . map ( |s| s. as_str ( ) ) ) ;
920+
838921 DocEntryCtx :: new (
839922 ctx,
840923 id,
@@ -846,7 +929,7 @@ fn render_class_property(
846929 ) ) ,
847930 & ts_type,
848931 tags,
849- property . js_doc . doc . as_deref ( ) ,
932+ doc,
850933 & property. location ,
851934 diff_status,
852935 old_content,
@@ -906,14 +989,15 @@ fn render_class_properties(
906989 properties : Vec < PropertyOrMethod > ,
907990 property_changes : Option < & PropertiesDiff > ,
908991 method_changes : Option < & MethodsDiff > ,
992+ inherited_docs : & HashMap < String , String > ,
909993) -> Vec < DocEntryCtx > {
910994 let mut properties = properties. into_iter ( ) . peekable ( ) ;
911995 let mut out = vec ! [ ] ;
912996
913997 while let Some ( property) = properties. next ( ) {
914998 let content = match property {
915999 PropertyOrMethod :: Property ( property) => {
916- render_class_property ( ctx, class_name, & property, property_changes)
1000+ render_class_property ( ctx, class_name, & property, property_changes, inherited_docs )
9171001 }
9181002 PropertyOrMethod :: Method ( method) => {
9191003 let ( getter, setter) = if method. kind == MethodKind :: Getter {
@@ -945,6 +1029,7 @@ fn render_class_properties(
9451029 getter,
9461030 setter. as_ref ( ) ,
9471031 method_changes,
1032+ inherited_docs,
9481033 )
9491034 }
9501035 } ;
@@ -1044,12 +1129,13 @@ fn render_class_methods(
10441129 class_name : & str ,
10451130 methods : BTreeMap < Box < str > , Vec < ClassMethodDef > > ,
10461131 method_changes : Option < & MethodsDiff > ,
1132+ inherited_docs : & HashMap < String , String > ,
10471133) -> Vec < DocEntryCtx > {
10481134 let mut out: Vec < DocEntryCtx > = methods
10491135 . values ( )
10501136 . flat_map ( |methods| {
10511137 methods. iter ( ) . enumerate ( ) . filter_map ( |( i, method) | {
1052- render_class_method ( ctx, class_name, method, i, method_changes)
1138+ render_class_method ( ctx, class_name, method, i, method_changes, inherited_docs )
10531139 } )
10541140 } )
10551141 . collect ( ) ;
0 commit comments