4
4
#[ cfg( test) ]
5
5
mod tests;
6
6
7
- use crate :: display:: { CodeDisplay , Lookup } ;
8
- use crate :: display:: { increase_header_level, parse_doc_for_summary} ;
7
+ use crate :: display:: { CodeDisplay , Lookup , increase_header_level, parse_doc_for_summary} ;
9
8
use crate :: table_of_contents:: table_of_contents;
10
9
use qsc_ast:: ast;
11
10
use qsc_data_structures:: language_features:: LanguageFeatures ;
@@ -15,6 +14,8 @@ use qsc_frontend::resolve;
15
14
use qsc_hir:: hir:: { CallableKind , Item , ItemKind , Package , PackageId , Res , Visibility } ;
16
15
use qsc_hir:: { hir, ty} ;
17
16
use rustc_hash:: FxHashMap ;
17
+ use std:: collections:: BTreeMap ;
18
+ use std:: fmt:: Write ;
18
19
use std:: fmt:: { Display , Formatter , Result } ;
19
20
use std:: rc:: Rc ;
20
21
use std:: sync:: Arc ;
@@ -276,46 +277,46 @@ impl Lookup for Compilation {
276
277
}
277
278
}
278
279
279
- /// Generates and returns documentation files for the standard library
280
- /// and additional sources (if specified.)
281
- #[ must_use]
282
- pub fn generate_docs (
283
- additional_sources : Option < ( PackageStore , & Dependencies , SourceMap ) > ,
284
- capabilities : Option < TargetCapabilityFlags > ,
285
- language_features : Option < LanguageFeatures > ,
286
- ) -> Files {
287
- // Capabilities should default to all capabilities for documentation generation.
288
- let capabilities = Some ( capabilities. unwrap_or ( TargetCapabilityFlags :: all ( ) ) ) ;
289
- let compilation = Compilation :: new ( additional_sources, capabilities, language_features) ;
290
- let mut files: FilesWithMetadata = vec ! [ ] ;
280
+ /// Determines the package kind for a given package in the compilation context
281
+ fn determine_package_kind ( package_id : PackageId , compilation : & Compilation ) -> Option < PackageKind > {
282
+ let is_current_package = compilation. current_package_id == Some ( package_id) ;
283
+
284
+ if package_id == PackageId :: CORE {
285
+ // Core package is always included in the compilation.
286
+ Some ( PackageKind :: Core )
287
+ } else if package_id == 1 . into ( ) {
288
+ // Standard package is currently always included, but this isn't enforced by the compiler.
289
+ Some ( PackageKind :: StandardLibrary )
290
+ } else if is_current_package {
291
+ // This package could be user code if current package is specified.
292
+ Some ( PackageKind :: UserCode )
293
+ } else {
294
+ // This is a either a direct dependency of the user code or
295
+ // is not a package user can access (an indirect dependency).
296
+ compilation
297
+ . dependencies
298
+ . get ( & package_id)
299
+ . map ( |alias| PackageKind :: AliasedPackage ( alias. to_string ( ) ) )
300
+ }
301
+ }
291
302
292
- let display = & CodeDisplay {
293
- compilation : & compilation,
294
- } ;
303
+ /// Processes all packages in a compilation and builds a table-of-contents structure
304
+ fn build_toc_from_compilation (
305
+ compilation : & Compilation ,
306
+ mut files : Option < & mut FilesWithMetadata > ,
307
+ ) -> ToC {
308
+ let display = & CodeDisplay { compilation } ;
295
309
296
310
let mut toc: ToC = FxHashMap :: default ( ) ;
297
311
298
312
for ( package_id, unit) in & compilation. package_store {
299
- let is_current_package = compilation. current_package_id == Some ( package_id) ;
300
- let package_kind;
301
- if package_id == PackageId :: CORE {
302
- // Core package is always included in the compilation.
303
- package_kind = PackageKind :: Core ;
304
- } else if package_id == 1 . into ( ) {
305
- // Standard package is currently always included, but this isn't enforced by the compiler.
306
- package_kind = PackageKind :: StandardLibrary ;
307
- } else if is_current_package {
308
- // This package could be user code if current package is specified.
309
- package_kind = PackageKind :: UserCode ;
310
- } else if let Some ( alias) = compilation. dependencies . get ( & package_id) {
311
- // This is a direct dependency of the user code.
312
- package_kind = PackageKind :: AliasedPackage ( alias. to_string ( ) ) ;
313
- } else {
314
- // This is not a package user can access (an indirect dependency).
313
+ let Some ( package_kind) = determine_package_kind ( package_id, compilation) else {
315
314
continue ;
316
- }
315
+ } ;
317
316
317
+ let is_current_package = compilation. current_package_id == Some ( package_id) ;
318
318
let package = & unit. package ;
319
+
319
320
for ( _, item) in & package. items {
320
321
if let Some ( ( ns, metadata) ) = generate_doc_for_item (
321
322
package_id,
@@ -324,13 +325,31 @@ pub fn generate_docs(
324
325
is_current_package,
325
326
item,
326
327
display,
327
- & mut files ,
328
+ files . as_deref_mut ( ) . unwrap_or ( & mut vec ! [ ] ) ,
328
329
) {
329
330
toc. entry ( ns) . or_default ( ) . push ( metadata) ;
330
331
}
331
332
}
332
333
}
333
334
335
+ toc
336
+ }
337
+
338
+ /// Generates and returns documentation files for the standard library
339
+ /// and additional sources (if specified.)
340
+ #[ must_use]
341
+ pub fn generate_docs (
342
+ additional_sources : Option < ( PackageStore , & Dependencies , SourceMap ) > ,
343
+ capabilities : Option < TargetCapabilityFlags > ,
344
+ language_features : Option < LanguageFeatures > ,
345
+ ) -> Files {
346
+ // Capabilities should default to all capabilities for documentation generation.
347
+ let capabilities = Some ( capabilities. unwrap_or ( TargetCapabilityFlags :: all ( ) ) ) ;
348
+ let compilation = Compilation :: new ( additional_sources, capabilities, language_features) ;
349
+ let mut files: FilesWithMetadata = vec ! [ ] ;
350
+
351
+ let mut toc = build_toc_from_compilation ( & compilation, Some ( & mut files) ) ;
352
+
334
353
// Generate Overview files for each namespace
335
354
for ( ns, items) in & mut toc {
336
355
generate_index_file ( & mut files, ns, items) ;
@@ -709,3 +728,74 @@ fn get_metadata(
709
728
signature,
710
729
} )
711
730
}
731
+
732
+ /// Generates summary documentation organized by namespace.
733
+ /// Returns a map of namespace -> metadata items for easier testing and manipulation.
734
+ fn generate_summaries_map ( ) -> BTreeMap < String , Vec < Rc < Metadata > > > {
735
+ let compilation = Compilation :: new ( None , None , None ) ;
736
+
737
+ // Use the shared logic to build ToC structure
738
+ let toc = build_toc_from_compilation ( & compilation, None ) ;
739
+
740
+ // Convert ToC to BTreeMap, filtering out table of contents entries
741
+ let mut result = BTreeMap :: new ( ) ;
742
+
743
+ for ( ns, items) in toc {
744
+ let mut summaries = Vec :: new ( ) ;
745
+
746
+ for item in items {
747
+ // Skip table of contents entries
748
+ if item. kind == MetadataKind :: TableOfContents {
749
+ continue ;
750
+ }
751
+
752
+ summaries. push ( item) ;
753
+ }
754
+
755
+ if !summaries. is_empty ( ) {
756
+ // Sort items within namespace
757
+ summaries. sort_by_key ( |item| item. name . clone ( ) ) ;
758
+ result. insert ( ns. to_string ( ) , summaries) ;
759
+ }
760
+ }
761
+
762
+ result
763
+ }
764
+ /// Converts a Metadata item to its markdown representation
765
+ fn metadata_to_markdown ( item : & Metadata ) -> String {
766
+ let mut result = format ! ( "## {}\n \n " , item. name) ;
767
+ let _ = write ! ( result, "```qsharp\n {}\n ```\n \n " , item. signature) ;
768
+ if !item. summary . is_empty ( ) {
769
+ let _ = write ! ( result, "{}\n \n " , item. summary) ;
770
+ }
771
+ result
772
+ }
773
+
774
+ /// Generates markdown summary for a single namespace
775
+ fn generate_namespace_summary ( namespace : & str , items : & [ Rc < Metadata > ] ) -> String {
776
+ let mut result = format ! ( "# {namespace}\n \n " ) ;
777
+
778
+ for item in items {
779
+ result. push_str ( & metadata_to_markdown ( item) ) ;
780
+ }
781
+
782
+ result
783
+ }
784
+
785
+ /// Generates summary documentation organized by namespace.
786
+ /// Returns a single markdown string with namespace headers and minimal item documentation
787
+ /// containing just function signatures and summaries for efficient consumption by language models.
788
+ #[ must_use]
789
+ pub fn generate_summaries ( ) -> String {
790
+ let summaries_map = generate_summaries_map ( ) ;
791
+
792
+ // Generate markdown output organized by namespace
793
+ let mut result = String :: new ( ) ;
794
+
795
+ // Sort namespaces for consistent output (BTreeMap already sorts keys)
796
+ for ( ns, items) in & summaries_map {
797
+ result. push_str ( & generate_namespace_summary ( ns, items) ) ;
798
+ }
799
+
800
+ result
801
+ }
0 commit comments