Skip to content

Commit 89bbdcd

Browse files
chore(ci): fix fmt, clippy, doc, test failures from Q2 PR
- fmt: rustfmt across new/modified files (test helpers, generator bin, ConstraintMode wiring). - clippy: - Convert `impl Default for <Strategy>` blocks to `#[derive(Default)]` + `#[default]` per-variant for all eight type-mapping strategy enums and ConstraintMode (clippy `derivable_impls`). - Replace literal U+200B chars in `format_constraints_doc`'s pattern escaping with the `\u{200B}` Rust escape (clippy `invisible_characters`). - doc: wrap `Vec<u8>` in backticks in the SchemaType::Primitive docstring (rustdoc `invalid_html_tags` treated `<u8>` as an unclosed HTML tag). - test: add `serde_with: ..` to a SchemaType::Primitive pattern match in `examples/number_formats.rs`, and add the new `types` field to the GeneratorConfig literal in `examples/complete_workflow.rs`. No behavior change. All four gates pass locally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 19493d0 commit 89bbdcd

13 files changed

Lines changed: 92 additions & 177 deletions

.beads/issues.jsonl

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

examples/complete_workflow.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ fn demonstrate_rust_api(
313313
schema_extensions: vec![],
314314
enable_registry: false,
315315
registry_only: false,
316+
types: openapi_to_rust::TypeMappingConfig::default(),
316317
};
317318

318319
// Generate code

examples/number_formats.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
8383
openapi_to_rust::analysis::SchemaType::Object { properties, .. } => {
8484
let mut prop_types = Vec::new();
8585
for (prop_name, prop_info) in properties {
86-
if let openapi_to_rust::analysis::SchemaType::Primitive { rust_type } =
87-
&prop_info.schema_type
86+
if let openapi_to_rust::analysis::SchemaType::Primitive {
87+
rust_type, ..
88+
} = &prop_info.schema_type
8889
{
8990
prop_types.push(format!("{prop_name}: {rust_type}"));
9091
} else {

src/analysis.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub enum SchemaType {
120120
/// Simple primitive type. `serde_with` carries an optional
121121
/// `#[serde(with = "<path>")]` codec hint produced by the
122122
/// TypeMapper for typed scalars (e.g. `format: byte` →
123-
/// Vec<u8> + `base64_serde`); the generator wraps this in a
123+
/// `Vec<u8>` + `base64_serde`); the generator wraps this in a
124124
/// field-level `with = ...` attribute.
125125
Primitive {
126126
rust_type: String,
@@ -1020,9 +1020,7 @@ impl SchemaAnalyzer {
10201020
SchemaType::ExtensibleEnum { known_values } => known_values.len(),
10211021
_ => continue,
10221022
};
1023-
if let Some(ext) =
1024-
extract_enum_extensions(&analyzed.original, enum_value_count, name)
1025-
{
1023+
if let Some(ext) = extract_enum_extensions(&analyzed.original, enum_value_count, name) {
10261024
analysis.enum_extensions.insert(name.clone(), ext);
10271025
}
10281026
}
@@ -1650,9 +1648,7 @@ impl SchemaAnalyzer {
16501648
description: prop_description,
16511649
default: prop_default,
16521650
serde_attrs: Vec::new(),
1653-
constraints: PropertyConstraints::from_schema_details(
1654-
prop_details,
1655-
),
1651+
constraints: PropertyConstraints::from_schema_details(prop_details),
16561652
},
16571653
);
16581654
continue;
@@ -1763,9 +1759,7 @@ impl SchemaAnalyzer {
17631759
Some(crate::openapi::AdditionalProperties::Boolean(false)) => {
17641760
ObjectAdditionalProperties::Forbidden
17651761
}
1766-
Some(crate::openapi::AdditionalProperties::Schema(value_schema))
1767-
if typed_enabled =>
1768-
{
1762+
Some(crate::openapi::AdditionalProperties::Schema(value_schema)) if typed_enabled => {
17691763
let analyzed =
17701764
self.analyze_property_schema_with_context(value_schema, None, dependencies)?;
17711765
ObjectAdditionalProperties::Typed {
@@ -3777,8 +3771,7 @@ impl SchemaAnalyzer {
37773771
.unwrap_or(true);
37783772

37793773
if primitive_unions {
3780-
let mapped =
3781-
self.type_mapper.map(schema_type.clone(), schema.details());
3774+
let mapped = self.type_mapper.map(schema_type.clone(), schema.details());
37823775
variants.push(SchemaRef {
37833776
target: mapped.rust_type,
37843777
nullable: false,
@@ -3817,8 +3810,8 @@ impl SchemaAnalyzer {
38173810
_ => format!("{context_name}Variant{inline_index}"),
38183811
};
38193812

3820-
let rust_type = self
3821-
.openapi_type_to_rust_type(schema_type.clone(), schema.details());
3813+
let rust_type =
3814+
self.openapi_type_to_rust_type(schema_type.clone(), schema.details());
38223815

38233816
self.resolved_cache.insert(
38243817
inline_type_name.clone(),

src/bin/openapi-to-rust.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
7777
// for bisecting regressions caused by typed-scalar
7878
// adoption without editing the TOML config.
7979
if types_conservative {
80-
generator_config.types =
81-
openapi_to_rust::TypeMappingConfig::conservative();
80+
generator_config.types = openapi_to_rust::TypeMappingConfig::conservative();
8281
}
8382

8483
println!(
@@ -132,8 +131,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
132131
// TypeMapper from the user's [generator.types] config so
133132
// per-format strategies drive type generation (Q2.0).
134133
println!("🔍 Analyzing schemas...");
135-
let type_mapper =
136-
openapi_to_rust::TypeMapper::new(generator_config.types.clone());
134+
let type_mapper = openapi_to_rust::TypeMapper::new(generator_config.types.clone());
137135
let mut analyzer = if generator_config.schema_extensions.is_empty() {
138136
SchemaAnalyzer::with_type_mapper(spec_value, type_mapper)?
139137
} else {

src/generator.rs

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ fn format_constraints_doc(c: &crate::analysis::PropertyConstraints) -> String {
6363
parts.push("uniqueItems=true".to_string());
6464
}
6565
if let Some(p) = &c.pattern {
66-
let safe = p.replace("///", "/​//").replace("*/", "*​/");
66+
// Insert a zero-width-space inside `///` and `*/` so they
67+
// can't terminate the surrounding doc/block comment. Using
68+
// the `\u{200B}` escape (vs. a literal U+200B) keeps clippy's
69+
// `invisible_characters` lint happy.
70+
let safe = p.replace("///", "/\u{200B}//").replace("*/", "*\u{200B}/");
6771
parts.push(format!("pattern=`{safe}`"));
6872
}
6973

@@ -768,9 +772,7 @@ impl CodeGenerator {
768772
// Skipped silently when the set is empty so we don't litter
769773
// the output dir for specs whose generated types only use
770774
// std/serde/serde_json.
771-
if let Some(toml) =
772-
crate::type_mapping::render_required_deps_toml(&result.required_deps)
773-
{
775+
if let Some(toml) = crate::type_mapping::render_required_deps_toml(&result.required_deps) {
774776
let deps_path = self.config.output_dir.join("REQUIRED_DEPS.toml");
775777
fs::write(&deps_path, toml)?;
776778
}
@@ -1128,31 +1130,32 @@ impl CodeGenerator {
11281130
})
11291131
.collect();
11301132

1131-
let variants = variant_pairs.iter().map(
1132-
|(variant_ident, value, is_default, description)| {
1133-
let doc = description
1134-
.as_ref()
1135-
.map(|d| {
1136-
let s = self.sanitize_doc_comment(d);
1137-
quote! { #[doc = #s] }
1138-
})
1139-
.unwrap_or_default();
1140-
if *is_default {
1141-
quote! {
1142-
#doc
1143-
#[default]
1144-
#[serde(rename = #value)]
1145-
#variant_ident,
1146-
}
1147-
} else {
1148-
quote! {
1149-
#doc
1150-
#[serde(rename = #value)]
1151-
#variant_ident,
1133+
let variants =
1134+
variant_pairs
1135+
.iter()
1136+
.map(|(variant_ident, value, is_default, description)| {
1137+
let doc = description
1138+
.as_ref()
1139+
.map(|d| {
1140+
let s = self.sanitize_doc_comment(d);
1141+
quote! { #[doc = #s] }
1142+
})
1143+
.unwrap_or_default();
1144+
if *is_default {
1145+
quote! {
1146+
#doc
1147+
#[default]
1148+
#[serde(rename = #value)]
1149+
#variant_ident,
1150+
}
1151+
} else {
1152+
quote! {
1153+
#doc
1154+
#[serde(rename = #value)]
1155+
#variant_ident,
1156+
}
11521157
}
1153-
}
1154-
},
1155-
);
1158+
});
11561159

11571160
// T13/T10: emit `as_str` and `Display` so the enum can be embedded in
11581161
// query strings, headers, and path segments without requiring callers

0 commit comments

Comments
 (0)