Skip to content

Commit 932a98c

Browse files
committed
Merge branch 'develop' into refactor/bitcoin-rpc
2 parents ebf676b + a9e2828 commit 932a98c

File tree

3 files changed

+76
-107
lines changed

3 files changed

+76
-107
lines changed

contrib/tools/config-docs-generator/generate-config-docs.sh

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ main() {
5757

5858
cd "$PROJECT_ROOT"
5959

60-
# Workaround for new nightly lint that breaks stacks-common build.
61-
# Allow callers to override or extend, but default to allowing the lint so documentation generation
62-
# stays green until codebase is updated.
63-
# TODO: Remove this once codebase will be updated to use the new lifetime syntax.
64-
export RUSTFLAGS="${RUSTFLAGS:-} -A mismatched-lifetime-syntaxes"
65-
6660
# Step 1: Build the documentation generation tools
6761
if [[ "$SKIP_BUILD" != "true" ]]; then
6862
log_info "Building documentation generation tools..."

contrib/tools/config-docs-generator/src/extract_docs.rs

Lines changed: 58 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ fn main() -> Result<()> {
134134
// Write the extracted docs to file
135135
fs::write(output_file, serde_json::to_string_pretty(&config_docs)?)?;
136136

137-
println!("Successfully extracted documentation to {}", output_file);
137+
println!("Successfully extracted documentation to {output_file}");
138138
println!(
139139
"Found {} structs with documentation",
140140
config_docs.structs.len()
@@ -183,10 +183,7 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
183183

184184
// Generate rustdoc for additional crates that might contain referenced constants
185185
for additional_crate in &additional_crates {
186-
let error_msg = format!(
187-
"Failed to run cargo rustdoc command for {}",
188-
additional_crate
189-
);
186+
let error_msg = format!("Failed to run cargo rustdoc command for {additional_crate}");
190187
let output = StdCommand::new("cargo")
191188
.args([
192189
"+nightly",
@@ -208,10 +205,7 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
208205

209206
if !output.status.success() {
210207
let stderr = String::from_utf8_lossy(&output.stderr);
211-
eprintln!(
212-
"Warning: Failed to generate rustdoc for {}: {}",
213-
additional_crate, stderr
214-
);
208+
eprintln!("Warning: Failed to generate rustdoc for {additional_crate}: {stderr}");
215209
}
216210
}
217211

@@ -225,7 +219,7 @@ fn generate_rustdoc_json(package: &str) -> Result<serde_json::Value> {
225219
};
226220

227221
// Read the generated JSON file - rustdoc generates it based on library name
228-
let json_file_path = format!("{}/doc/{}.json", rustdoc_target_dir, lib_name);
222+
let json_file_path = format!("{rustdoc_target_dir}/doc/{lib_name}.json");
229223
let json_content = std::fs::read_to_string(json_file_path)
230224
.context("Failed to read generated rustdoc JSON file")?;
231225

@@ -249,10 +243,10 @@ fn extract_config_docs_from_rustdoc(
249243
// Check if this item is a struct by looking for the "struct" field
250244
if get_json_object(item, &["inner", "struct"]).is_some() {
251245
// Check if this struct is in our target list (if specified)
252-
if let Some(targets) = target_structs {
253-
if !targets.contains(&name.to_string()) {
254-
continue;
255-
}
246+
if let Some(targets) = target_structs
247+
&& !targets.contains(&name.to_string())
248+
{
249+
continue;
256250
}
257251

258252
let (struct_doc_opt, referenced_constants) =
@@ -464,8 +458,7 @@ fn parse_field_documentation(
464458
"" => false, // Empty string defaults to false
465459
text => text.parse::<bool>().unwrap_or_else(|_| {
466460
eprintln!(
467-
"Warning: Invalid @required value '{}' for field '{}', defaulting to false",
468-
text, field_name
461+
"Warning: Invalid @required value '{text}' for field '{field_name}', defaulting to false"
469462
);
470463
false
471464
}),
@@ -632,14 +625,14 @@ fn parse_folded_block_scalar(lines: &[&str], _base_indent: usize) -> String {
632625
// Remove trailing empty lines but preserve a single trailing newline if content exists
633626
let trimmed = result.trim_end_matches('\n');
634627
if !trimmed.is_empty() && result.ends_with('\n') {
635-
format!("{}\n", trimmed)
628+
format!("{trimmed}\n")
636629
} else {
637630
trimmed.to_string()
638631
}
639632
}
640633

641634
fn extract_annotation(metadata_section: &str, annotation_name: &str) -> Option<String> {
642-
let annotation_pattern = format!("@{}:", annotation_name);
635+
let annotation_pattern = format!("@{annotation_name}:");
643636

644637
if let Some(_start_pos) = metadata_section.find(&annotation_pattern) {
645638
// Split the metadata section into lines for processing
@@ -820,15 +813,13 @@ fn resolve_constant_reference(
820813
let additional_crate_libs = ["stacks_common"]; // Library names for additional crates
821814

822815
for lib_name in &additional_crate_libs {
823-
let json_file_path = format!("target/rustdoc-json/doc/{}.json", lib_name);
824-
if let Ok(json_content) = std::fs::read_to_string(&json_file_path) {
825-
if let Ok(rustdoc_json) = serde_json::from_str::<serde_json::Value>(&json_content) {
826-
if let Some(index) = get_json_object(&rustdoc_json, &["index"]) {
827-
if let Some(value) = resolve_constant_in_index(name, index) {
828-
return Some(value);
829-
}
830-
}
831-
}
816+
let json_file_path = format!("target/rustdoc-json/doc/{lib_name}.json");
817+
if let Ok(json_content) = std::fs::read_to_string(&json_file_path)
818+
&& let Ok(rustdoc_json) = serde_json::from_str::<serde_json::Value>(&json_content)
819+
&& let Some(index) = get_json_object(&rustdoc_json, &["index"])
820+
&& let Some(value) = resolve_constant_in_index(name, index)
821+
{
822+
return Some(value);
832823
}
833824
}
834825

@@ -842,61 +833,57 @@ fn resolve_constant_in_index(
842833
// Look for a constant with the given name in the rustdoc index
843834
for (_item_id, item) in rustdoc_index {
844835
// Check if this item's name matches the constant we're looking for
845-
if let Some(item_name) = get_json_string(item, &["name"]) {
846-
if item_name == name {
847-
// Check if this item is a constant by looking for the "constant" field
848-
if let Some(constant_data) = get_json_object(item, &["inner", "constant"]) {
849-
// Try newer rustdoc JSON structure first (with nested 'const' field)
850-
let constant_data_value = serde_json::Value::Object(constant_data.clone());
851-
if get_json_object(&constant_data_value, &["const"]).is_some() {
852-
// For literal constants, prefer expr which doesn't have type suffix
853-
if get_json_path(&constant_data_value, &["const", "is_literal"])
854-
.and_then(|v| v.as_bool())
855-
== Some(true)
856-
{
857-
// Access the expression field for literal constant values
858-
if let Some(expr) =
859-
get_json_string(&constant_data_value, &["const", "expr"])
860-
{
861-
if expr != "_" {
862-
return Some(expr.to_string());
863-
}
864-
}
865-
}
866-
867-
// For computed constants or when expr is "_", use value but strip type suffix
868-
if let Some(value) =
869-
get_json_string(&constant_data_value, &["const", "value"])
870-
{
871-
return Some(strip_type_suffix(value));
872-
}
873-
874-
// Fallback to expr if value is not available
836+
if let Some(item_name) = get_json_string(item, &["name"])
837+
&& item_name == name
838+
{
839+
// Check if this item is a constant by looking for the "constant" field
840+
if let Some(constant_data) = get_json_object(item, &["inner", "constant"]) {
841+
// Try newer rustdoc JSON structure first (with nested 'const' field)
842+
let constant_data_value = serde_json::Value::Object(constant_data.clone());
843+
if get_json_object(&constant_data_value, &["const"]).is_some() {
844+
// For literal constants, prefer expr which doesn't have type suffix
845+
if get_json_path(&constant_data_value, &["const", "is_literal"])
846+
.and_then(|v| v.as_bool())
847+
== Some(true)
848+
{
849+
// Access the expression field for literal constant values
875850
if let Some(expr) =
876851
get_json_string(&constant_data_value, &["const", "expr"])
852+
&& expr != "_"
877853
{
878-
if expr != "_" {
879-
return Some(expr.to_string());
880-
}
854+
return Some(expr.to_string());
881855
}
882856
}
883857

884-
// Fall back to older rustdoc JSON structure for compatibility
885-
if let Some(value) = get_json_string(&constant_data_value, &["value"]) {
858+
// For computed constants or when expr is "_", use value but strip type suffix
859+
if let Some(value) = get_json_string(&constant_data_value, &["const", "value"])
860+
{
886861
return Some(strip_type_suffix(value));
887862
}
888-
if let Some(expr) = get_json_string(&constant_data_value, &["expr"]) {
889-
if expr != "_" {
890-
return Some(expr.to_string());
891-
}
892-
}
893863

894-
// For some constants, the value might be in the type field if it's a simple literal
895-
if let Some(type_str) = get_json_string(&constant_data_value, &["type"]) {
896-
// Handle simple numeric or string literals embedded in type
897-
return Some(type_str.to_string());
864+
// Fallback to expr if value is not available
865+
if let Some(expr) = get_json_string(&constant_data_value, &["const", "expr"])
866+
&& expr != "_"
867+
{
868+
return Some(expr.to_string());
898869
}
899870
}
871+
872+
// Fall back to older rustdoc JSON structure for compatibility
873+
if let Some(value) = get_json_string(&constant_data_value, &["value"]) {
874+
return Some(strip_type_suffix(value));
875+
}
876+
if let Some(expr) = get_json_string(&constant_data_value, &["expr"])
877+
&& expr != "_"
878+
{
879+
return Some(expr.to_string());
880+
}
881+
882+
// For some constants, the value might be in the type field if it's a simple literal
883+
if let Some(type_str) = get_json_string(&constant_data_value, &["type"]) {
884+
// Handle simple numeric or string literals embedded in type
885+
return Some(type_str.to_string());
886+
}
900887
}
901888
}
902889
}

contrib/tools/config-docs-generator/src/generate_markdown.rs

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ fn main() -> Result<()> {
103103
let mappings_path = matches.get_one::<String>("mappings").unwrap();
104104

105105
let input_content = fs::read_to_string(input_path)
106-
.with_context(|| format!("Failed to read input JSON file: {}", input_path))?;
106+
.with_context(|| format!("Failed to read input JSON file: {input_path}"))?;
107107

108108
let config_docs: ConfigDocs =
109109
serde_json::from_str(&input_content).with_context(|| "Failed to parse input JSON")?;
@@ -113,43 +113,32 @@ fn main() -> Result<()> {
113113
let markdown = generate_markdown(&config_docs, template_path, &custom_mappings)?;
114114

115115
fs::write(output_path, markdown)
116-
.with_context(|| format!("Failed to write output file: {}", output_path))?;
116+
.with_context(|| format!("Failed to write output file: {output_path}"))?;
117117

118-
println!(
119-
"Successfully generated Markdown documentation at {}",
120-
output_path
121-
);
118+
println!("Successfully generated Markdown documentation at {output_path}");
122119
Ok(())
123120
}
124121

125122
fn load_section_name_mappings(mappings_file: &str) -> Result<HashMap<String, String>> {
126-
let content = fs::read_to_string(mappings_file).with_context(|| {
127-
format!(
128-
"Failed to read section name mappings file: {}",
129-
mappings_file
130-
)
131-
})?;
123+
let content = fs::read_to_string(mappings_file)
124+
.with_context(|| format!("Failed to read section name mappings file: {mappings_file}"))?;
132125

133-
let mappings: HashMap<String, String> = serde_json::from_str(&content).with_context(|| {
134-
format!(
135-
"Failed to parse section name mappings JSON: {}",
136-
mappings_file
137-
)
138-
})?;
126+
let mappings: HashMap<String, String> = serde_json::from_str(&content)
127+
.with_context(|| format!("Failed to parse section name mappings JSON: {mappings_file}"))?;
139128

140129
Ok(mappings)
141130
}
142131

143132
fn load_template(template_path: &str) -> Result<String> {
144133
fs::read_to_string(template_path)
145-
.with_context(|| format!("Failed to read template file: {}", template_path))
134+
.with_context(|| format!("Failed to read template file: {template_path}"))
146135
}
147136

148137
fn render_template(template: &str, variables: HashMap<String, String>) -> String {
149138
let mut result = template.to_string();
150139

151140
for (key, value) in variables {
152-
let placeholder = format!("{{{{{}}}}}", key);
141+
let placeholder = format!("{{{{{key}}}}}");
153142
result = result.replace(&placeholder, &value);
154143
}
155144

@@ -245,7 +234,7 @@ fn generate_struct_section(
245234
custom_mappings: &HashMap<String, String>,
246235
) -> Result<()> {
247236
let section_name = struct_to_section_name(&struct_doc.name, custom_mappings);
248-
output.push_str(&format!("## {}\n\n", section_name));
237+
output.push_str(&format!("## {section_name}\n\n"));
249238

250239
// Add struct description if available
251240
if let Some(description) = &struct_doc.description {
@@ -365,7 +354,7 @@ fn generate_field_row(
365354

366355
// Add deprecation warning if present
367356
if let Some(deprecated) = &field.deprecated {
368-
description_parts.push(format!("<br><br>**⚠️ DEPRECATED:** {}", deprecated));
357+
description_parts.push(format!("<br><br>**⚠️ DEPRECATED:** {deprecated}"));
369358
}
370359

371360
// Add TOML example if present
@@ -385,16 +374,15 @@ fn generate_field_row(
385374
.replace('\n', "&#10;"); // Use HTML entity for newline to avoid <br> conversion
386375

387376
let example_section = format!(
388-
"<br><br>**Example:**<br><pre><code>{}</code></pre>",
389-
escaped_example // HTML entities will be rendered as newlines by <pre>
377+
"<br><br>**Example:**<br><pre><code>{escaped_example}</code></pre>" // HTML entities will be rendered as newlines by <pre>
390378
);
391379
description_parts.push(example_section);
392380
}
393381

394382
// Add units information if present
395383
if let Some(units) = &field.units {
396384
let units_text = process_intralinks_with_context(units, global_context, struct_name);
397-
description_parts.push(format!("<br><br>**Units:** {}", units_text));
385+
description_parts.push(format!("<br><br>**Units:** {units_text}"));
398386
}
399387

400388
let description = if description_parts.is_empty() {
@@ -513,11 +501,11 @@ fn process_reference(
513501
// Check if it's the same struct or different struct
514502
if ref_struct_name == current_struct_name {
515503
// Same struct: just show field name
516-
return format!("[{}](#{}) ", field_name, anchor_id);
504+
return format!("[{field_name}](#{anchor_id}) ");
517505
} else {
518506
// Different struct: show [config_section].field_name as a link
519507
let config_section = section_name.trim_start_matches('[').trim_end_matches(']');
520-
return format!("[[{}].{}](#{}) ", config_section, field_name, anchor_id);
508+
return format!("[[{config_section}].{field_name}](#{anchor_id}) ");
521509
}
522510
}
523511
}
@@ -540,11 +528,11 @@ fn process_reference(
540528
// Check if it's the same struct or different struct
541529
if field_struct_name == current_struct_name {
542530
// Same struct: just show field name
543-
return format!("[{}](#{}) ", reference, anchor_id);
531+
return format!("[{reference}](#{anchor_id}) ");
544532
} else {
545533
// Different struct: show [config_section].field_name as a link
546534
let config_section = section_name.trim_start_matches('[').trim_end_matches(']');
547-
return format!("[[{}].{}](#{}) ", config_section, reference, anchor_id);
535+
return format!("[[{config_section}].{reference}](#{anchor_id}) ");
548536
}
549537
}
550538
}
@@ -577,7 +565,7 @@ fn process_hierarchical_lists(
577565
let processed_content =
578566
process_intralinks_with_context(content, global_context, struct_name);
579567

580-
result.push(format!("{}{}", indent_html, processed_content));
568+
result.push(format!("{indent_html}{processed_content}"));
581569
} else {
582570
// Process intra-links in non-bullet lines too
583571
let processed_line = process_intralinks_with_context(line, global_context, struct_name);

0 commit comments

Comments
 (0)