openapi_nexus_typescript/templating/
templates.rs1use minijinja::Environment;
5use serde::{Deserialize, Serialize};
6
7use super::environment::create_template_environment;
8use crate::errors::GeneratorError;
9use openapi_nexus_common::GeneratorType;
10use openapi_nexus_core::traits::FileCategory;
11use openapi_nexus_core::traits::file_writer::FileInfo;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub enum TemplateName {
18 #[serde(rename = "README.md.j2")]
21 Readme,
22
23 #[serde(rename = "api/operation.j2")]
26 ApiOperation,
27
28 #[serde(rename = "model/interface.j2")]
31 ModelInterface,
32 #[serde(rename = "model/type_alias.j2")]
34 ModelTypeAlias,
35 #[serde(rename = "model/enum.j2")]
37 ModelEnum,
38
39 #[serde(rename = "runtime/runtime.j2")]
42 Runtime,
43
44 #[serde(rename = "project/index.j2")]
47 ProjectIndex,
48
49 #[serde(rename = "common/file_header.j2")]
53 CommonFileHeader,
54 #[serde(rename = "api/snippets/constructor_base_api.j2")]
56 ApiConstructorBaseApi,
57 #[serde(rename = "api/snippets/method_get.j2")]
59 ApiMethodGet,
60 #[serde(rename = "api/snippets/method_post_put_patch.j2")]
62 ApiMethodPostPutPatch,
63 #[serde(rename = "api/snippets/method_delete.j2")]
65 ApiMethodDelete,
66 #[serde(rename = "api/snippets/method_convenience.j2")]
68 ApiMethodConvenience,
69 #[serde(rename = "api/snippets/build_url_path.j2")]
71 ApiBuildUrlPath,
72 #[serde(rename = "api/snippets/build_query_params.j2")]
74 ApiBuildQueryParams,
75 #[serde(rename = "api/snippets/build_headers.j2")]
77 ApiBuildHeaders,
78 #[serde(rename = "api/snippets/build_request_body.j2")]
80 ApiBuildRequestBody,
81 #[serde(rename = "api/snippets/make_request.j2")]
83 ApiMakeRequest,
84 #[serde(rename = "model/snippets/interface_helpers.j2")]
86 ModelInferenceHelpers,
87}
88
89impl TemplateName {
90 pub fn file_path(&self) -> String {
92 serde_plain::to_string(self)
93 .expect("TemplateName should always serialize to a valid string")
94 }
95
96 pub fn resolve_path(&self, generator_name: &str) -> String {
100 let path = self.file_path();
101 if self.file_category() != FileCategory::None {
102 format!("{}/{}", generator_name, path)
103 } else {
104 path
105 }
106 }
107
108 pub fn file_category(&self) -> FileCategory {
110 match self {
111 Self::Readme => FileCategory::Readme,
113
114 Self::ApiOperation => FileCategory::Apis,
116
117 Self::ModelInterface => FileCategory::Models,
119 Self::ModelTypeAlias => FileCategory::Models,
120 Self::ModelEnum => FileCategory::Models,
121
122 Self::Runtime => FileCategory::Runtime,
124
125 Self::ProjectIndex => FileCategory::ProjectFiles,
127
128 Self::CommonFileHeader
131 | Self::ApiConstructorBaseApi
132 | Self::ApiMethodGet
133 | Self::ApiMethodPostPutPatch
134 | Self::ApiMethodDelete
135 | Self::ApiMethodConvenience
136 | Self::ApiBuildUrlPath
137 | Self::ApiBuildQueryParams
138 | Self::ApiBuildHeaders
139 | Self::ApiBuildRequestBody
140 | Self::ApiMakeRequest
141 | Self::ModelInferenceHelpers => FileCategory::None,
142 }
143 }
144}
145
146pub const TEMPLATE_PATHS: &[TemplateName] = &[
149 TemplateName::Readme,
151 TemplateName::ApiOperation,
153 TemplateName::ModelEnum,
155 TemplateName::ModelInterface,
156 TemplateName::ModelTypeAlias,
157 TemplateName::Runtime,
159 TemplateName::ProjectIndex,
161 TemplateName::ApiBuildHeaders,
163 TemplateName::ApiBuildQueryParams,
164 TemplateName::ApiBuildRequestBody,
165 TemplateName::ApiBuildUrlPath,
166 TemplateName::ApiConstructorBaseApi,
167 TemplateName::ApiMakeRequest,
168 TemplateName::ApiMethodConvenience,
169 TemplateName::ApiMethodDelete,
170 TemplateName::ApiMethodGet,
171 TemplateName::ApiMethodPostPutPatch,
172 TemplateName::CommonFileHeader,
173 TemplateName::ModelInferenceHelpers,
174];
175
176#[derive(Debug, Clone)]
179pub struct Templates {
180 env: Environment<'static>,
181 generator_name: String,
182}
183
184impl Templates {
185 pub fn new(generator: GeneratorType) -> Self {
189 let env = create_template_environment();
190 let generator_name = generator.to_string();
191 Self {
192 env,
193 generator_name,
194 }
195 }
196
197 pub fn render_template(
198 &self,
199 template_name: TemplateName,
200 output_filename: &str,
201 context: minijinja::Value,
202 ) -> Result<FileInfo, GeneratorError> {
203 let template_path = template_name.resolve_path(&self.generator_name);
204 let template = self.env.get_template(&template_path).map_err(|e| {
205 GeneratorError::TemplateNotFound {
206 template_path: template_path.clone(),
207 source: e,
208 }
209 })?;
210 let content = template
211 .render(context)
212 .map_err(|e| GeneratorError::TemplateRender {
213 template_path: template_path.clone(),
214 source: e,
215 })?;
216
217 Ok(FileInfo::new(
218 output_filename.to_string(),
219 content,
220 template_name.file_category(),
221 ))
222 }
223
224 pub fn render_template_string(
226 &self,
227 template_name: TemplateName,
228 context: minijinja::Value,
229 ) -> Result<String, GeneratorError> {
230 let template_path = template_name.resolve_path(&self.generator_name);
231 let template = self.env.get_template(&template_path).map_err(|e| {
232 GeneratorError::TemplateNotFound {
233 template_path: template_path.clone(),
234 source: e,
235 }
236 })?;
237 template
238 .render(context)
239 .map_err(|e| GeneratorError::TemplateRender {
240 template_path: template_path.clone(),
241 source: e,
242 })
243 }
244}