11use crate :: db:: ScarbDocDatabase ;
2+ use crate :: location_links:: DocLocationLink ;
23use crate :: types:: module_type:: is_doc_hidden_attr;
34use crate :: types:: other_types:: doc_full_path;
45use crate :: types:: item_data:: ItemData ;
56use cairo_lang_defs:: ids:: {
6- LanguageElementId , LookupItemId , MemberId , ModuleItemId , NamedLanguageElementId , StructId ,
7+ LanguageElementId , LookupItemId , MemberId , ModuleItemId , NamedLanguageElementId , StructId , TopLevelLanguageElementId ,
78} ;
89use cairo_lang_diagnostics:: Maybe ;
10+ use cairo_lang_doc:: db:: DocGroup ;
911use cairo_lang_doc:: documentable_item:: DocumentableItemId ;
12+ use cairo_lang_doc:: helpers:: {
13+ get_generic_params, get_struct_attributes_syntax, get_syntactic_visibility,
14+ } ;
15+ use cairo_lang_doc:: location_links:: { LocationLink , format_signature} ;
16+ use cairo_lang_doc:: signature_data:: SignatureDataRetriever ;
1017use cairo_lang_semantic:: items:: structure:: StructSemantic ;
1118use cairo_lang_semantic:: items:: visibility:: Visibility ;
1219use cairo_lang_syntax:: node:: ast;
@@ -30,31 +37,19 @@ impl<'db> Struct<'db> {
3037 id : StructId < ' db > ,
3138 include_private_items : bool ,
3239 ) -> Maybe < Self > {
33- let members = db. struct_members ( id) ?;
34-
35- let item_data = ItemData :: new (
40+ let mut item_data = ItemData :: new_without_signature (
3641 db,
3742 id,
3843 LookupItemId :: ModuleItem ( ModuleItemId :: Struct ( id) ) . into ( ) ,
39- doc_full_path ( & id. parent_module ( db) , db) ,
4044 ) ;
41- let members = members
42- . iter ( )
43- . filter_map ( |( _, semantic_member) | {
44- let visible = matches ! ( semantic_member. visibility, Visibility :: Public ) ;
45- let syntax_node = & semantic_member. id . stable_location ( db) . syntax_node ( db) ;
46- if ( include_private_items || visible) && !is_doc_hidden_attr ( db, syntax_node) {
47- Some ( Ok ( Member :: new ( db, semantic_member. id ) ) )
48- } else {
49- None
50- }
51- } )
52- . collect :: < Maybe < Vec < _ > > > ( ) ?;
45+ let mut signature_builder = StructSignatureBuilder :: new ( db, id, include_private_items) ;
46+ let ( signature, location_links, members) = signature_builder. build_signature ( db) ;
47+ item_data. signature = Some ( signature) ;
48+ item_data. doc_location_links = location_links;
5349
54- let node = id. stable_ptr ( db) ;
5550 Ok ( Self {
5651 id,
57- node,
52+ node : id . stable_ptr ( db ) ,
5853 members,
5954 item_data,
6055 } )
@@ -68,6 +63,146 @@ impl<'db> Struct<'db> {
6863 }
6964}
7065
66+ struct MemberDataHelper < ' db > {
67+ signature : Option < String > ,
68+ member_id : MemberId < ' db > ,
69+ location_links : Vec < LocationLink < ' db > > ,
70+ }
71+
72+ impl < ' db > MemberDataHelper < ' db > {
73+ fn new ( member_id : MemberId < ' db > , db : & ' db ScarbDocDatabase ) -> Self {
74+ let ( signature, location_links) =
75+ db. get_item_signature_with_links ( DocumentableItemId :: Member ( member_id) ) ;
76+ Self {
77+ signature,
78+ member_id,
79+ location_links,
80+ }
81+ }
82+ }
83+
84+ struct StructSignatureBuilder < ' a > {
85+ members_data : Vec < MemberDataHelper < ' a > > ,
86+ has_private_members : bool ,
87+ has_public_members : bool ,
88+ buff : String ,
89+ location_links : Vec < LocationLink < ' a > > ,
90+ }
91+
92+ impl < ' db > StructSignatureBuilder < ' db > {
93+ const INDENT : & ' static str = " " ;
94+ const PRIVATE_MEMBERS : & ' static str = "/* private fields */" ;
95+
96+ fn new ( db : & ' db ScarbDocDatabase , id : StructId < ' db > , include_private_items : bool ) -> Self {
97+ let members = db. struct_members ( id)
98+ . expect ( & format ! ( "Failed to get members of struct: {}" , id. full_path( db) ) ) ;
99+ let signature_data = StructId :: retrieve_signature_data ( db, id)
100+ . expect ( & format ! ( "Failed to get signature data for struct: {}" , id. full_path( db) ) ) ;
101+
102+ let mut buff = String :: new ( ) ;
103+ let mut location_links = Vec :: new ( ) ;
104+
105+ if let Some ( attributes) = signature_data. attributes {
106+ let attributes_syntax = get_struct_attributes_syntax ( attributes, db)
107+ . expect ( & format ! ( "Failed to format attributes syntax for struct: {}" , id. full_path( db) ) ) ;
108+
109+ buff. push_str ( & attributes_syntax) ;
110+ }
111+ buff. push_str ( & format ! (
112+ "{}struct {}" ,
113+ get_syntactic_visibility( & signature_data. visibility) ,
114+ signature_data. name. long( db)
115+ ) ) ;
116+
117+ if let Some ( generic_params) = signature_data. generic_params {
118+ let ( stx, _location_links) = get_generic_params ( generic_params, db)
119+ . expect ( & format ! ( "Failed to get format params for struct: {}" , id. full_path( db) ) ) ;
120+
121+ buff. push_str ( & stx) ;
122+ location_links. extend ( _location_links) ;
123+ }
124+ let mut has_private_members = false ;
125+ let mut has_public_members = false ;
126+
127+ let members_data: Vec < MemberDataHelper > = members
128+ . iter ( )
129+ . filter_map ( |( _, semantic_member) | {
130+ let visible = matches ! ( semantic_member. visibility, Visibility :: Public ) ;
131+ let syntax_node = & semantic_member. id . stable_location ( db) . syntax_node ( db) ;
132+
133+ if ( include_private_items || visible) && !is_doc_hidden_attr ( db, syntax_node) {
134+ let mdh = MemberDataHelper :: new ( semantic_member. id , db) ;
135+ has_public_members = true ;
136+ Some ( Ok ( mdh) )
137+ } else {
138+ has_private_members = true ;
139+ None
140+ }
141+ } )
142+ . collect :: < Maybe < Vec < _ > > > ( )
143+ . expect ( & format ! ( "Failed to collect members data for struct: {}" , id. full_path( db) ) ) ;
144+
145+ StructSignatureBuilder {
146+ members_data,
147+ has_private_members,
148+ has_public_members,
149+ buff,
150+ location_links,
151+ }
152+ }
153+
154+ fn build_signature (
155+ & mut self ,
156+ db : & ' db ScarbDocDatabase ,
157+ ) -> ( String , Vec < DocLocationLink > , Vec < Member < ' db > > ) {
158+ let mut members = Vec :: new ( ) ;
159+ self . buff . push_str ( " {" ) ;
160+
161+ for mdh in & self . members_data {
162+ members. push ( Member :: new ( db, mdh. member_id ) ) ;
163+ let mut offset = self . buff . len ( ) ;
164+ offset += "\n " . len ( ) + Self :: INDENT . len ( ) ;
165+
166+ let formatted_member_signature = format ! (
167+ "\n {}{}," ,
168+ Self :: INDENT ,
169+ mdh. signature. clone( ) . unwrap_or_default( )
170+ ) ;
171+ self . buff . push_str ( & formatted_member_signature) ;
172+ self . location_links . extend (
173+ mdh. location_links
174+ . iter ( )
175+ . map ( |link| LocationLink :: new ( link. start , link. end , link. item_id , offset) )
176+ . collect :: < Vec < _ > > ( ) ,
177+ ) ;
178+ }
179+
180+ if !& self . members_data . is_empty ( ) {
181+ self . buff . push ( '\n' ) ;
182+ }
183+
184+ if self . has_private_members {
185+ let ( prefix, postfix) = if self . has_public_members {
186+ ( Self :: INDENT , "\n " )
187+ } else {
188+ ( " " , " " )
189+ } ;
190+ self . buff . push_str ( & format ! ( "{prefix}{}{postfix}" , Self :: PRIVATE_MEMBERS ) ) ;
191+ }
192+ self . buff . push ( '}' ) ;
193+
194+ let ( new_sig_formatted, formatted_location_links) =
195+ format_signature ( db, self . buff . clone ( ) , self . location_links . clone ( ) ) ;
196+
197+ let doc_location_links = formatted_location_links
198+ . iter ( )
199+ . map ( |link| DocLocationLink :: new ( link. start , link. end , link. item_id , db) )
200+ . collect :: < Vec < _ > > ( ) ;
201+
202+ ( new_sig_formatted, doc_location_links, members)
203+ }
204+ }
205+
71206#[ derive( Serialize , Clone ) ]
72207pub struct Member < ' db > {
73208 #[ serde( skip) ]
0 commit comments