openapi_nexus_config/
typescript_config.rs1use std::fmt;
4use std::str::FromStr;
5
6use clap::Args;
7use serde::{Deserialize, Serialize};
8
9use openapi_nexus_core::NamingConvention;
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub enum TypeScriptModule {
14 CommonJS,
15 ESNext,
16 ES2020,
17 ES2022,
18}
19
20impl FromStr for TypeScriptModule {
21 type Err = String;
22
23 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 match s.to_lowercase().as_str() {
25 "commonjs" | "cjs" => Ok(Self::CommonJS),
26 "esnext" => Ok(Self::ESNext),
27 "es2020" => Ok(Self::ES2020),
28 "es2022" => Ok(Self::ES2022),
29 _ => Err(format!(
30 "Invalid TypeScript module: '{}'. Expected one of: commonjs, esnext, es2020, es2022",
31 s
32 )),
33 }
34 }
35}
36
37impl fmt::Display for TypeScriptModule {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 TypeScriptModule::CommonJS => write!(f, "commonjs"),
41 TypeScriptModule::ESNext => write!(f, "esnext"),
42 TypeScriptModule::ES2020 => write!(f, "es2020"),
43 TypeScriptModule::ES2022 => write!(f, "es2022"),
44 }
45 }
46}
47
48#[derive(Debug, Clone, Args, Serialize, Deserialize)]
50#[command(next_help_heading = "TypeScript Options")]
51pub struct TypeScriptConfig {
52 #[arg(long = "ts-file-naming-convention", env = "OPENAPI_NEXUS_TS_FILE_NAMING_CONVENTION", default_value_t = default_file_naming_convention())]
54 #[serde(default = "default_file_naming_convention")]
55 pub file_naming_convention: NamingConvention,
56
57 #[arg(long = "ts-package-scope", env = "OPENAPI_NEXUS_TS_PACKAGE_SCOPE")]
59 #[serde(default)]
60 pub package_scope: Option<String>,
61
62 #[arg(long = "ts-package-name", env = "OPENAPI_NEXUS_TS_PACKAGE_NAME")]
64 #[serde(default)]
65 pub package_name: Option<String>,
66
67 #[arg(long = "ts-generate-package", env = "OPENAPI_NEXUS_TS_GENERATE_PACKAGE", default_value_t = default_generate_package())]
69 #[serde(default = "default_generate_package")]
70 pub generate_package: bool,
71
72 #[arg(long = "ts-target", env = "OPENAPI_NEXUS_TS_TARGET", default_value_t = default_typescript_target())]
74 #[serde(default = "default_typescript_target")]
75 pub ts_target: String,
76
77 #[arg(long = "ts-module", env = "OPENAPI_NEXUS_TS_MODULE", value_parser = TypeScriptModule::from_str, default_value_t = default_typescript_module())]
79 #[serde(default = "default_typescript_module")]
80 pub ts_module: TypeScriptModule,
81
82 #[arg(long = "ts-lib", env = "OPENAPI_NEXUS_TS_LIB", value_delimiter = ',')]
84 #[serde(default, deserialize_with = "deserialize_string_vec")]
85 pub ts_lib: Option<Vec<String>>,
86
87 #[arg(long = "ts-generate-esm-config", env = "OPENAPI_NEXUS_TS_GENERATE_ESM_CONFIG", default_value_t = default_generate_esm_config())]
89 #[serde(default = "default_generate_esm_config")]
90 pub generate_esm_config: bool,
91
92 #[arg(long = "ts-include-build-scripts", env = "OPENAPI_NEXUS_TS_INCLUDE_BUILD_SCRIPTS", default_value_t = default_include_build_scripts())]
94 #[serde(default = "default_include_build_scripts")]
95 pub include_build_scripts: bool,
96}
97
98fn default_file_naming_convention() -> NamingConvention {
99 NamingConvention::PascalCase
100}
101
102fn default_generate_package() -> bool {
103 true
104}
105
106fn default_typescript_target() -> String {
107 "es6".to_string()
108}
109
110fn default_typescript_module() -> TypeScriptModule {
111 TypeScriptModule::CommonJS
112}
113
114fn default_generate_esm_config() -> bool {
115 true
116}
117
118fn default_include_build_scripts() -> bool {
119 false
120}
121
122fn deserialize_string_vec<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
124where
125 D: serde::Deserializer<'de>,
126{
127 use serde::Deserialize;
128
129 #[derive(Deserialize)]
130 #[serde(untagged)]
131 enum StringVec {
132 Array(Vec<String>),
133 String(String),
134 }
135
136 match StringVec::deserialize(deserializer)? {
137 StringVec::Array(vec) => Ok(Some(vec)),
138 StringVec::String(s) => {
139 if s.is_empty() {
140 Ok(None)
141 } else {
142 Ok(Some(s.split(',').map(|s| s.trim().to_string()).collect()))
143 }
144 }
145 }
146}
147
148impl Default for TypeScriptConfig {
149 fn default() -> Self {
150 Self {
151 file_naming_convention: default_file_naming_convention(),
152 package_scope: None,
153 package_name: None,
154 generate_package: default_generate_package(),
155 ts_target: default_typescript_target(),
156 ts_module: default_typescript_module(),
157 ts_lib: None,
158 generate_esm_config: default_generate_esm_config(),
159 include_build_scripts: default_include_build_scripts(),
160 }
161 }
162}