@@ -75,7 +75,7 @@ fn main() -> Result<()> {
75
75
. long ( "structs" )
76
76
. value_name ( "NAMES" )
77
77
. help ( "Comma-separated list of struct names to extract" )
78
- . required ( false ) ,
78
+ . required ( true ) ,
79
79
)
80
80
. get_matches ( ) ;
81
81
@@ -109,6 +109,11 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
109
109
// constants referenced in doc comments are added to the project
110
110
let additional_crates = [ "stacks-common" ] ;
111
111
112
+ // Respect CARGO_TARGET_DIR environment variable for rustdoc output
113
+ let rustdoc_target_dir = std:: env:: var ( "CARGO_TARGET_DIR" )
114
+ . unwrap_or_else ( |_| "target" . to_string ( ) )
115
+ + "/rustdoc-json" ;
116
+
112
117
// WARNING: This tool relies on nightly rustdoc JSON output (-Z unstable-options --output-format json)
113
118
// The JSON format is subject to change with new Rust nightly versions and could break this tool.
114
119
// Use cargo rustdoc with nightly to generate JSON for the main package
@@ -120,7 +125,7 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
120
125
"-p" ,
121
126
package,
122
127
"--target-dir" ,
123
- "target/rustdoc-json" ,
128
+ & rustdoc_target_dir ,
124
129
"--" ,
125
130
"-Z" ,
126
131
"unstable-options" ,
@@ -150,7 +155,7 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
150
155
"-p" ,
151
156
additional_crate,
152
157
"--target-dir" ,
153
- "target/rustdoc-json" ,
158
+ & rustdoc_target_dir ,
154
159
"--" ,
155
160
"-Z" ,
156
161
"unstable-options" ,
@@ -180,7 +185,7 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
180
185
} ;
181
186
182
187
// Read the generated JSON file - rustdoc generates it based on library name
183
- let json_file_path = format ! ( "target/rustdoc-json/ doc/{}.json" , lib_name) ;
188
+ let json_file_path = format ! ( "{}/ doc/{}.json" , rustdoc_target_dir , lib_name) ;
184
189
let json_content = std:: fs:: read_to_string ( json_file_path)
185
190
. context ( "Failed to read generated rustdoc JSON file" ) ?;
186
191
@@ -443,7 +448,10 @@ fn parse_field_documentation(
443
448
"false" | "no" | "0" => false ,
444
449
_ => {
445
450
// Default to false for invalid values, but could log a warning in the future
446
- eprintln ! ( "Warning: Invalid @required value '{}' for field '{}', defaulting to false" , required_text, field_name) ;
451
+ eprintln ! (
452
+ "Warning: Invalid @required value '{}' for field '{}', defaulting to false" ,
453
+ required_text, field_name
454
+ ) ;
447
455
false
448
456
}
449
457
} ;
@@ -480,7 +488,8 @@ fn parse_literal_block_scalar(lines: &[&str], _base_indent: usize) -> String {
480
488
}
481
489
482
490
// Find the first non-empty content line to determine block indentation
483
- let content_lines: Vec < & str > = lines. iter ( )
491
+ let content_lines: Vec < & str > = lines
492
+ . iter ( )
484
493
. skip_while ( |line| line. trim ( ) . is_empty ( ) )
485
494
. copied ( )
486
495
. collect ( ) ;
@@ -531,7 +540,8 @@ fn parse_folded_block_scalar(lines: &[&str], _base_indent: usize) -> String {
531
540
}
532
541
533
542
// Find the first non-empty content line to determine block indentation
534
- let content_lines: Vec < & str > = lines. iter ( )
543
+ let content_lines: Vec < & str > = lines
544
+ . iter ( )
535
545
. skip_while ( |line| line. trim ( ) . is_empty ( ) )
536
546
. copied ( )
537
547
. collect ( ) ;
@@ -642,7 +652,11 @@ fn extract_annotation(metadata_section: &str, annotation_name: &str) -> Option<S
642
652
if trimmed_after_colon. starts_with ( '|' ) {
643
653
// Literal block scalar mode (|)
644
654
// Content starts from the next line, ignoring any text after | on the same line
645
- let block_lines = collect_annotation_block_lines ( & all_lines, annotation_line_idx + 1 , annotation_line) ;
655
+ let block_lines = collect_annotation_block_lines (
656
+ & all_lines,
657
+ annotation_line_idx + 1 ,
658
+ annotation_line,
659
+ ) ;
646
660
647
661
// Convert to owned strings for the parser
648
662
let owned_lines: Vec < String > = block_lines. iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
@@ -659,7 +673,11 @@ fn extract_annotation(metadata_section: &str, annotation_name: &str) -> Option<S
659
673
} else if trimmed_after_colon. starts_with ( '>' ) {
660
674
// Folded block scalar mode (>)
661
675
// Content starts from the next line, ignoring any text after > on the same line
662
- let block_lines = collect_annotation_block_lines ( & all_lines, annotation_line_idx + 1 , annotation_line) ;
676
+ let block_lines = collect_annotation_block_lines (
677
+ & all_lines,
678
+ annotation_line_idx + 1 ,
679
+ annotation_line,
680
+ ) ;
663
681
664
682
// Convert to owned strings for the parser
665
683
let owned_lines: Vec < String > = block_lines. iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
@@ -684,7 +702,11 @@ fn extract_annotation(metadata_section: &str, annotation_name: &str) -> Option<S
684
702
}
685
703
686
704
// Collect subsequent lines that belong to this annotation
687
- let block_lines = collect_annotation_block_lines ( & all_lines, annotation_line_idx + 1 , annotation_line) ;
705
+ let block_lines = collect_annotation_block_lines (
706
+ & all_lines,
707
+ annotation_line_idx + 1 ,
708
+ annotation_line,
709
+ ) ;
688
710
689
711
// For default mode, preserve relative indentation within the block
690
712
if !block_lines. is_empty ( ) {
@@ -741,7 +763,7 @@ fn extract_annotation(metadata_section: &str, annotation_name: &str) -> Option<S
741
763
fn collect_annotation_block_lines < ' a > (
742
764
all_lines : & [ & ' a str ] ,
743
765
start_idx : usize ,
744
- annotation_line : & str
766
+ annotation_line : & str ,
745
767
) -> Vec < & ' a str > {
746
768
let mut block_lines = Vec :: new ( ) ;
747
769
let annotation_indent = annotation_line. len ( ) - annotation_line. trim_start ( ) . len ( ) ;
@@ -2108,7 +2130,10 @@ and includes various formatting.
2108
2130
let result = parse_field_documentation ( doc_text, "test_field" ) . unwrap ( ) ;
2109
2131
2110
2132
assert_eq ! ( result. 0 . name, "test_field" ) ;
2111
- assert_eq ! ( result. 0 . description, "Field with required and units annotations." ) ;
2133
+ assert_eq ! (
2134
+ result. 0 . description,
2135
+ "Field with required and units annotations."
2136
+ ) ;
2112
2137
assert_eq ! ( result. 0 . default_value, Some ( "`5000`" . to_string( ) ) ) ;
2113
2138
assert_eq ! ( result. 0 . required, Some ( true ) ) ;
2114
2139
assert_eq ! ( result. 0 . units, Some ( "milliseconds" . to_string( ) ) ) ;
@@ -2232,7 +2257,10 @@ and includes various formatting.
2232
2257
let result = parse_field_documentation ( doc_text, "test_field" ) . unwrap ( ) ;
2233
2258
let ( field_doc, referenced_constants) = result;
2234
2259
2235
- assert_eq ! ( field_doc. units, Some ( "[`DEFAULT_TIMEOUT_MS`] milliseconds" . to_string( ) ) ) ;
2260
+ assert_eq ! (
2261
+ field_doc. units,
2262
+ Some ( "[`DEFAULT_TIMEOUT_MS`] milliseconds" . to_string( ) )
2263
+ ) ;
2236
2264
// Check that constants were collected from units
2237
2265
assert ! ( referenced_constants. contains( "DEFAULT_TIMEOUT_MS" ) ) ;
2238
2266
}
@@ -2402,7 +2430,10 @@ and includes various formatting.
2402
2430
// Test empty @required annotation (should return None, not Some(false))
2403
2431
let doc_text_empty = "Test field.\n ---\n @required:" ;
2404
2432
let result_empty = parse_field_documentation ( doc_text_empty, "test_field" ) . unwrap ( ) ;
2405
- assert_eq ! ( result_empty. 0 . required, None , "Empty @required should not be parsed" ) ;
2433
+ assert_eq ! (
2434
+ result_empty. 0 . required, None ,
2435
+ "Empty @required should not be parsed"
2436
+ ) ;
2406
2437
}
2407
2438
2408
2439
#[ test]
0 commit comments