use std::path::PathBuf;
use crate::error::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Runtime {
#[default]
Prost,
Buffa,
}
#[derive(Debug, Clone)]
pub struct ModelsPath {
template: String,
}
impl ModelsPath {
pub fn new(template: &str) -> Result<Self> {
let test = template
.replace("{service}", "test")
.replace("{version}", "v1");
syn::parse_str::<syn::Path>(&test).map_err(|e| Error::InvalidModelsPathTemplate {
template: template.to_string(),
source: e,
})?;
Ok(Self::from_template(template))
}
pub(crate) fn from_template(template: &str) -> Self {
Self {
template: template.to_string(),
}
}
pub fn try_resolve(&self, service: &str, version: &str) -> Result<syn::Path> {
let path = self.substitute(service, version);
syn::parse_str(&path).map_err(|source| Error::InvalidModelsPathTemplate {
template: path,
source,
})
}
pub fn validate_for(&self, service: &str) -> Result<()> {
self.try_resolve(service, "v1").map(|_| ())
}
pub fn resolve(&self, service: &str, version: &str) -> syn::Path {
let path = self.substitute(service, version);
syn::parse_str(&path)
.unwrap_or_else(|e| panic!("Invalid models path `{path}` after substitution: {e}"))
}
fn substitute(&self, service: &str, version: &str) -> String {
self.template
.replace("{service}", service)
.replace("{version}", version)
}
}
#[derive(Debug, Clone)]
pub struct BindingsConfig {
pub aggregate_client_name: String,
pub client_crate_name: String,
pub py_error_type: String,
pub py_result_type: String,
pub napi_error_ext_trait: String,
pub typings_package_filter: Option<String>,
pub ts_error_base_class: String,
pub ts_error_code_prefix: String,
}
#[derive(Debug, Clone)]
pub struct CodeGenConfig {
pub context_type_path: String,
pub result_type_path: String,
pub models_path_template: String,
pub models_path_crate_template: String,
pub output: CodeGenOutput,
pub generate_resource_enum: bool,
pub generate_store_integration: bool,
pub error_type_path: Option<String>,
pub generate_object_conversions: bool,
pub bindings: Option<BindingsConfig>,
pub resource_store_crate_name: String,
pub runtime: Runtime,
pub transport_type_path: String,
}
pub const DEFAULT_TRANSPORT_TYPE_PATH: &str = "olai_http::CloudClient";
impl CodeGenConfig {
pub fn uses_default_transport(&self) -> bool {
self.transport_type_path == DEFAULT_TRANSPORT_TYPE_PATH
}
pub fn dual_transport(&self) -> bool {
self.output.wasm.is_some()
}
pub fn validate(&self) -> Result<()> {
ModelsPath::new(&self.models_path_template)?;
ModelsPath::new(&self.models_path_crate_template)?;
if (self.output.python.is_some()
|| self.output.node.is_some()
|| self.output.node_ts.is_some()
|| self.output.wasm.is_some())
&& self.bindings.is_none()
{
return Err(Error::MissingBindingsConfig);
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct CodeGenOutput {
pub common: PathBuf,
pub models: Option<PathBuf>,
pub models_subdir: String,
pub server: Option<PathBuf>,
pub client: Option<PathBuf>,
pub generate_resource_clients: bool,
pub python: Option<PathBuf>,
pub node: Option<PathBuf>,
pub node_ts: Option<PathBuf>,
pub wasm: Option<PathBuf>,
pub python_typings_filename: String,
}
impl CodeGenOutput {
pub fn models_subdir_path(&self) -> Option<PathBuf> {
self.models.as_ref().map(|m| m.join(&self.models_subdir))
}
}