#![deny(rust_2018_idioms)]
#![warn(missing_docs)]
use std::path::Path;
pub mod emit;
pub mod error;
pub mod ir;
pub mod parsers;
pub use error::{GenError, Result};
pub use ir::{ApiKind, ApiSpec};
pub fn generate_from_path(
spec_path: &Path,
kind: Option<ApiKind>,
output_dir: &Path,
crate_name: Option<&str>,
) -> Result<emit::EmitReport> {
let kind = kind
.or_else(|| ApiKind::infer_from_path(spec_path))
.ok_or_else(|| GenError::Parse {
kind: "auto-detect",
message: format!(
"could not infer API kind from {:?}; pass --kind explicitly",
spec_path
),
})?;
let raw = std::fs::read_to_string(spec_path).map_err(|source| GenError::ReadSpec {
path: spec_path.to_path_buf(),
source,
})?;
let mut spec = match kind {
ApiKind::OpenApi => parsers::openapi::parse(&raw)?,
ApiKind::GraphQl => parsers::graphql::parse(&raw)?,
ApiKind::Grpc => parsers::proto::parse(&raw)?,
};
spec.raw_spec = Some(raw);
if let Some(name) = crate_name {
spec.name = name.to_string();
}
emit::emit_crate(&spec, output_dir)
}
impl ApiKind {
pub fn infer_from_path(path: &Path) -> Option<Self> {
let ext = path.extension()?.to_str()?.to_ascii_lowercase();
Some(match ext.as_str() {
"yaml" | "yml" | "json" => ApiKind::OpenApi,
"graphql" | "graphqls" | "gql" => ApiKind::GraphQl,
"proto" => ApiKind::Grpc,
_ => return None,
})
}
}