Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ applied. Non-required properties with types that already have a default value
(such as a `Vec<T>`) simply get the `#[serde(default)]` attribute (so you won't
see e.g. `Option<Vec<T>>`).

#### Alternate Map types

By default, Typify uses `std::collections::HashMap` as described above.

If you prefer to use `std::collections::BTreeMap` or a map type from a crate such
as `indexmap::IndexMap`, you can specify this by calling `with_map_type` on the
`TypeSpaceSettings` object, and providing the full path to the type you want to
use. E.g. `::std::collections::BTreeMap` or `::indexmap::IndexMap`.

Note that for a custom map type to work you must have `T` defined to generate
a struct as described in [Objects](#objects). If `T` is not defined, typify
will generate code using a `serde_json::Map<String, serde_json::Value>` instead.

See the documentation for `TypeSpaceSettings::with_map_type` for the
requirements for a map type.

### OneOf

The `oneOf` construct maps to a Rust enum. Typify maps this to the various
Expand Down
33 changes: 33 additions & 0 deletions cargo-typify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ pub struct CliArgs {
#[arg(long = "crate")]
crates: Vec<CrateSpec>,

/// Specify the map like type to use.
#[arg(long = "map-type")]
map_type: Option<String>,

/// Specify the policy unknown crates found in schemas with the
/// x-rust-type extension.
#[arg(
Expand Down Expand Up @@ -151,6 +155,10 @@ pub fn convert(args: &CliArgs) -> Result<String> {
settings.with_crate(name, version.clone(), rename.as_ref());
}

if let Some(map_type) = &args.map_type {
settings.with_map_type(map_type.clone());
}

if let Some(unknown_crates) = &args.unknown_crates {
let unknown_crates = match unknown_crates.as_str() {
"generate" => UnknownPolicy::Generate,
Expand Down Expand Up @@ -192,6 +200,7 @@ mod tests {
output: Some(PathBuf::from("-")),
no_builder: false,
crates: vec![],
map_type: None,
unknown_crates: Default::default(),
};

Expand All @@ -207,6 +216,7 @@ mod tests {
output: Some(PathBuf::from("some_file.rs")),
no_builder: false,
crates: vec![],
map_type: None,
unknown_crates: Default::default(),
};

Expand All @@ -222,12 +232,32 @@ mod tests {
output: None,
no_builder: false,
crates: vec![],
map_type: None,
unknown_crates: Default::default(),
};

assert_eq!(args.output_path(), Some(PathBuf::from("input.rs")));
}

#[test]
fn test_use_btree_map() {
let args = CliArgs {
input: PathBuf::from("input.json"),
builder: false,
additional_derives: vec![],
output: None,
no_builder: false,
crates: vec![],
map_type: Some("::std::collections::BTreeMap".to_string()),
unknown_crates: Default::default(),
};

assert_eq!(
args.map_type,
Some("::std::collections::BTreeMap".to_string())
);
}

#[test]
fn test_builder_as_default_style() {
let args = CliArgs {
Expand All @@ -237,6 +267,7 @@ mod tests {
output: None,
no_builder: false,
crates: vec![],
map_type: None,
unknown_crates: Default::default(),
};

Expand All @@ -252,6 +283,7 @@ mod tests {
output: None,
no_builder: true,
crates: vec![],
map_type: None,
unknown_crates: Default::default(),
};

Expand All @@ -267,6 +299,7 @@ mod tests {
output: None,
no_builder: false,
crates: vec![],
map_type: None,
unknown_crates: Default::default(),
};

Expand Down
26 changes: 26 additions & 0 deletions cargo-typify/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,29 @@ fn test_help() {
assert!(output.status.success());
assert_contents("tests/outputs/help.txt", &actual);
}

#[test]
fn test_btree_map() {
use assert_cmd::Command;

let input = concat!(env!("CARGO_MANIFEST_DIR"), "/../example.json");

let temp = TempDir::new("cargo-typify").unwrap();
let output_file = temp.path().join("output.rs");

let mut cmd = Command::cargo_bin("cargo-typify").unwrap();
cmd.args([
"typify",
input,
"--map-type",
"::std::collections::BTreeMap",
"--output",
output_file.to_str().unwrap(),
])
.assert()
.success();

let actual = std::fs::read_to_string(output_file).unwrap();

assert_contents("tests/outputs/custom_btree_map.rs", &actual);
}
19 changes: 12 additions & 7 deletions cargo-typify/tests/outputs/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,22 @@ pub mod error {
#[doc = r""]
#[doc = r" ```json"]
#[doc = "{"]
#[doc = " \"type\": \"object\""]
#[doc = " \"type\": \"object\","]
#[doc = " \"additionalProperties\": {"]
#[doc = " \"type\": \"string\""]
#[doc = " }"]
#[doc = "}"]
#[doc = r" ```"]
#[doc = r" </details>"]
#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)]
pub struct Fruit(pub ::serde_json::Map<::std::string::String, ::serde_json::Value>);
pub struct Fruit(pub ::std::collections::HashMap<::std::string::String, ::std::string::String>);
impl ::std::ops::Deref for Fruit {
type Target = ::serde_json::Map<::std::string::String, ::serde_json::Value>;
fn deref(&self) -> &::serde_json::Map<::std::string::String, ::serde_json::Value> {
type Target = ::std::collections::HashMap<::std::string::String, ::std::string::String>;
fn deref(&self) -> &::std::collections::HashMap<::std::string::String, ::std::string::String> {
&self.0
}
}
impl From<Fruit> for ::serde_json::Map<::std::string::String, ::serde_json::Value> {
impl From<Fruit> for ::std::collections::HashMap<::std::string::String, ::std::string::String> {
fn from(value: Fruit) -> Self {
value.0
}
Expand All @@ -57,8 +60,10 @@ impl From<&Fruit> for Fruit {
value.clone()
}
}
impl From<::serde_json::Map<::std::string::String, ::serde_json::Value>> for Fruit {
fn from(value: ::serde_json::Map<::std::string::String, ::serde_json::Value>) -> Self {
impl From<::std::collections::HashMap<::std::string::String, ::std::string::String>> for Fruit {
fn from(
value: ::std::collections::HashMap<::std::string::String, ::std::string::String>,
) -> Self {
Self(value)
}
}
Expand Down
Loading
Loading