openapi_nexus_typescript/templating/
templates.rs1use minijinja::Environment;
5use serde::{Deserialize, Serialize};
6
7use super::environment::create_template_environment;
8use crate::emission::error::EmitError;
9use openapi_nexus_core::traits::FileCategory;
10use openapi_nexus_core::traits::file_writer::FileInfo;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
16pub enum TemplateName {
17 #[serde(rename = "README.md.j2")]
20 Readme,
21
22 #[serde(rename = "api/operation.j2")]
25 ApiOperation,
26
27 #[serde(rename = "model/interface.j2")]
30 ModelInterface,
31 #[serde(rename = "model/type_alias.j2")]
33 ModelTypeAlias,
34 #[serde(rename = "model/enum.j2")]
36 ModelEnum,
37
38 #[serde(rename = "runtime/runtime.j2")]
41 Runtime,
42
43 #[serde(rename = "project/index.j2")]
46 ProjectIndex,
47
48 #[serde(rename = "common/file_header.j2")]
52 CommonFileHeader,
53 #[serde(rename = "api/snippets/constructor_base_api.j2")]
55 ApiConstructorBaseApi,
56 #[serde(rename = "api/snippets/method_get.j2")]
58 ApiMethodGet,
59 #[serde(rename = "api/snippets/method_post_put_patch.j2")]
61 ApiMethodPostPutPatch,
62 #[serde(rename = "api/snippets/method_delete.j2")]
64 ApiMethodDelete,
65 #[serde(rename = "api/snippets/method_convenience.j2")]
67 ApiMethodConvenience,
68 #[serde(rename = "api/snippets/build_url_path.j2")]
70 ApiBuildUrlPath,
71 #[serde(rename = "api/snippets/build_query_params.j2")]
73 ApiBuildQueryParams,
74 #[serde(rename = "api/snippets/build_headers.j2")]
76 ApiBuildHeaders,
77 #[serde(rename = "api/snippets/build_request_body.j2")]
79 ApiBuildRequestBody,
80 #[serde(rename = "api/snippets/make_request.j2")]
82 ApiMakeRequest,
83 #[serde(rename = "model/snippets/interface_helpers.j2")]
85 ModelInferenceHelpers,
86}
87
88impl TemplateName {
89 pub fn file_path(&self) -> String {
91 serde_plain::to_string(self)
92 .expect("TemplateName should always serialize to a valid string")
93 }
94
95 pub fn file_category(&self) -> FileCategory {
97 match self {
98 Self::Readme => FileCategory::Readme,
100
101 Self::ApiOperation => FileCategory::Apis,
103
104 Self::ModelInterface => FileCategory::Models,
106 Self::ModelTypeAlias => FileCategory::Models,
107 Self::ModelEnum => FileCategory::Models,
108
109 Self::Runtime => FileCategory::Runtime,
111
112 Self::ProjectIndex => FileCategory::ProjectFiles,
114
115 Self::CommonFileHeader
118 | Self::ApiConstructorBaseApi
119 | Self::ApiMethodGet
120 | Self::ApiMethodPostPutPatch
121 | Self::ApiMethodDelete
122 | Self::ApiMethodConvenience
123 | Self::ApiBuildUrlPath
124 | Self::ApiBuildQueryParams
125 | Self::ApiBuildHeaders
126 | Self::ApiBuildRequestBody
127 | Self::ApiMakeRequest
128 | Self::ModelInferenceHelpers => FileCategory::None,
129 }
130 }
131}
132
133pub const TEMPLATE_PATHS: &[TemplateName] = &[
136 TemplateName::Readme,
138 TemplateName::ApiOperation,
140 TemplateName::ModelEnum,
142 TemplateName::ModelInterface,
143 TemplateName::ModelTypeAlias,
144 TemplateName::Runtime,
146 TemplateName::ProjectIndex,
148 TemplateName::ApiBuildHeaders,
150 TemplateName::ApiBuildQueryParams,
151 TemplateName::ApiBuildRequestBody,
152 TemplateName::ApiBuildUrlPath,
153 TemplateName::ApiConstructorBaseApi,
154 TemplateName::ApiMakeRequest,
155 TemplateName::ApiMethodConvenience,
156 TemplateName::ApiMethodDelete,
157 TemplateName::ApiMethodGet,
158 TemplateName::ApiMethodPostPutPatch,
159 TemplateName::CommonFileHeader,
160 TemplateName::ModelInferenceHelpers,
161];
162
163#[derive(Debug, Clone)]
166pub struct Templates {
167 env: Environment<'static>,
168}
169
170impl Default for Templates {
171 fn default() -> Self {
172 Self::new()
173 }
174}
175
176impl Templates {
177 pub fn new() -> Self {
181 let env = create_template_environment();
182 Self { env }
183 }
184
185 pub fn render_template(
186 &self,
187 template_name: TemplateName,
188 output_filename: &str,
189 context: minijinja::Value,
190 ) -> Result<FileInfo, EmitError> {
191 let template_path = template_name.file_path();
192 let template = self.env.get_template(&template_path).map_err(|e| {
193 let err = EmitError::TemplateError {
194 message: format!("Failed to get {} template: {}", template_path, e),
195 };
196 tracing::error!("{}", err);
197 err
198 })?;
199 let content = template.render(context).map_err(|e| {
200 let err = EmitError::TemplateError {
201 message: format!("Failed to render {} template: {}", template_path, e),
202 };
203 tracing::error!("{}", err);
204 err
205 })?;
206
207 Ok(FileInfo::new(
208 output_filename.to_string(),
209 content,
210 template_name.file_category(),
211 ))
212 }
213
214 pub fn render_template_string(
216 &self,
217 template_name: TemplateName,
218 context: minijinja::Value,
219 ) -> Result<String, EmitError> {
220 let template_path = template_name.file_path();
221 let template = self.env.get_template(&template_path).map_err(|e| {
222 let err = EmitError::TemplateError {
223 message: format!("Failed to get {} template: {}", template_path, e),
224 };
225 tracing::error!("{}", err);
226 err
227 })?;
228 template.render(context).map_err(|e| {
229 let err = EmitError::TemplateError {
230 message: format!("Failed to render {} template: {}", template_path, e),
231 };
232 tracing::error!("{}", err);
233 err
234 })
235 }
236}