weld_codegen/
config.rs

1use std::{collections::BTreeMap, fmt, path::PathBuf, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4use toml::Value as TomlValue;
5
6use crate::error::Error;
7
8/// Output languages for code generation
9#[non_exhaustive]
10#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
11#[serde(rename_all = "lowercase")]
12pub enum OutputLanguage {
13    /// used for code generation of language-independent project files
14    Poly,
15    /// HTML documentation
16    Html,
17    /// Rust
18    Rust,
19    /// AssemblyScript (not currently supported)
20    AssemblyScript,
21    /// TinyGo (not currently supported)
22    TinyGo,
23    /// Go (not currently supported)
24    Go,
25    /// Python
26    Python,
27    /// C++ (not currently supported)
28    Clang,
29}
30
31impl std::str::FromStr for OutputLanguage {
32    type Err = Error;
33
34    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
35        match s.to_ascii_lowercase().as_str() {
36            "poly" => Ok(OutputLanguage::Poly),
37            "html" => Ok(OutputLanguage::Html),
38            "rust" => Ok(OutputLanguage::Rust),
39            "assemblyscript" => Ok(OutputLanguage::AssemblyScript),
40            "tinygo" => Ok(OutputLanguage::TinyGo),
41            "go" => Ok(OutputLanguage::Go),
42            "python" => Ok(OutputLanguage::Python),
43            "c++" | "clang" => Ok(OutputLanguage::Clang),
44            _ => Err(Error::UnsupportedLanguage(s.to_string())),
45        }
46    }
47}
48
49impl fmt::Display for OutputLanguage {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(
52            f,
53            "{}",
54            match self {
55                OutputLanguage::Poly => "Poly",
56                OutputLanguage::Html => "Html",
57                OutputLanguage::Rust => "Rust",
58                OutputLanguage::AssemblyScript => "AssemblyScript",
59                OutputLanguage::TinyGo => "TinyGo",
60                OutputLanguage::Go => "Go",
61                OutputLanguage::Python => "Python",
62                OutputLanguage::Clang => "Clang",
63            }
64        )
65    }
66}
67
68impl OutputLanguage {
69    // returns the primary extension for the langauge
70    pub fn extension(&self) -> &'static str {
71        match self {
72            OutputLanguage::Rust => "rs",
73            OutputLanguage::TinyGo | OutputLanguage::Go => "go",
74            OutputLanguage::AssemblyScript => "rs",
75            OutputLanguage::Python => "rs",
76            OutputLanguage::Poly => "",
77            OutputLanguage::Html => "html",
78            OutputLanguage::Clang => "c",
79        }
80    }
81}
82
83#[derive(Debug, Deserialize, Serialize)]
84pub struct CodegenConfig {
85    /// model inputs
86    #[serde(default)]
87    pub models: Vec<ModelSource>,
88
89    /// This can be set by the cli to limit the languages generated.
90    /// Without this flag, all languages in the toml file are generated.
91    #[serde(default)]
92    pub output_languages: Vec<OutputLanguage>,
93
94    /// Language-specific output configuration
95    #[serde(flatten)]
96    pub languages: BTreeMap<OutputLanguage, LanguageConfig>,
97
98    /// The directory containing the codegen.toml file, and the base_dir
99    /// used for evaluating all relative paths in the file.
100    /// This is not set inside the toml file but is set by the file reader,
101    /// It is always set to an absolute path
102    #[serde(default)]
103    pub base_dir: PathBuf,
104}
105
106/// Source directory or url prefix for finding model files
107/// For Paths, the `path` and `files` can be model files, or directories, which will
108/// be searched recursively for model files with `.json` or `.smithy` extensions.
109/// `files` array is optional if url or path directly references a model file,
110#[derive(Debug, Deserialize, Serialize)]
111#[serde(untagged)]
112pub enum ModelSource {
113    Url {
114        url: String,
115        #[serde(default)]
116        files: Vec<String>,
117    },
118    Path {
119        path: PathBuf,
120        #[serde(default)]
121        files: Vec<String>,
122    },
123}
124
125pub enum ModelSourceKind {
126    Url(String),
127    Path(PathBuf),
128}
129
130impl FromStr for ModelSource {
131    type Err = std::convert::Infallible;
132
133    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
134        Ok(if s.starts_with("https:") || s.starts_with("http:") {
135            ModelSource::Url {
136                url: s.to_string(),
137                files: Vec::default(),
138            }
139        } else {
140            ModelSource::Path { path: s.into(), files: Vec::default() }
141        })
142    }
143}
144
145impl ModelSource {
146    /// convenience function to create a ModelSource for a single file path
147    pub fn from_file<P: Into<std::path::PathBuf>>(path: P) -> ModelSource {
148        ModelSource::Path { path: path.into(), files: Vec::default() }
149    }
150}
151
152impl fmt::Display for ModelSource {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(
155            f,
156            "{}",
157            match self {
158                ModelSource::Url { url, files: _ } => format!("url({url})"),
159                ModelSource::Path { path, files: _ } => format!("path({})", path.display()),
160            }
161        )
162    }
163}
164
165#[derive(Debug, Default, Deserialize, Serialize)]
166pub struct LanguageConfig {
167    /// list of template files or template folders for importing templates.
168    /// Overwrites any compiled-in templates with the same name(s)
169    #[serde(default)]
170    pub templates: Option<PathBuf>,
171
172    /// Output directory. Required.
173    /// (with weld cli, this will be relative to the output-dir on the command line)
174    pub output_dir: PathBuf,
175
176    /// Additional parameters
177    #[serde(default)]
178    pub parameters: BTreeMap<String, TomlValue>,
179
180    /// source-code formatter
181    /// first item in vec should be program, rest are args
182    /// For languages other than rust, the formatter _only_ runs if defined in codegen.toml
183    /// example: [ "goimports", "-w" ]
184    /// example: [ "rustfmt", "--edition", "2021" ]
185    #[serde(default)]
186    pub formatter: Vec<String>,
187
188    /// Settings specific to individual output files
189    #[serde(default)]
190    pub files: Vec<OutputFile>,
191}
192
193/// Output-file specific settings
194#[derive(Debug, Default, Deserialize, Serialize)]
195pub struct OutputFile {
196    /// path to output file, relative to language output_dir. Required.
197    pub path: PathBuf,
198
199    /// name of handlebars template file (without hbs extension)
200    /// Not used for files generated by codegen
201    #[serde(default)]
202    pub hbs: Option<String>,
203
204    /// True if file should be generated only for 'create' operations
205    #[serde(default)]
206    pub create_only: bool,
207
208    /// Optionally, limit code generation for this file to shapes in this namespace
209    #[serde(default)]
210    pub namespace: Option<String>,
211
212    /// optional additional parameters for this file
213    #[serde(flatten)]
214    pub params: BTreeMap<String, TomlValue>,
215}
216
217impl FromStr for CodegenConfig {
218    type Err = Error;
219
220    fn from_str(content: &str) -> std::result::Result<CodegenConfig, Self::Err> {
221        let config = toml::from_str(content).map_err(|e| Error::Other(format!("codegen: {e}")))?;
222        Ok(config)
223    }
224}