mcp_execution_codegen/common/
types.rs

1//! Types for code generation.
2//!
3//! Defines the data structures used during code generation from MCP
4//! tool schemas to executable TypeScript or Rust code.
5//!
6//! # Examples
7//!
8//! ```
9//! use mcp_execution_codegen::{GeneratedCode, GeneratedFile};
10//!
11//! let file = GeneratedFile {
12//!     path: "tools/sendMessage.ts".to_string(),
13//!     content: "export function sendMessage() {}".to_string(),
14//! };
15//!
16//! let code = GeneratedCode {
17//!     files: vec![file],
18//! };
19//!
20//! assert_eq!(code.files.len(), 1);
21//! ```
22
23use serde::{Deserialize, Serialize};
24use std::collections::HashMap;
25
26/// Result of code generation containing all generated files.
27///
28/// This is the main output type returned by the code generator.
29/// Contains a list of files that should be written to disk.
30///
31/// # Examples
32///
33/// ```
34/// use mcp_execution_codegen::GeneratedCode;
35///
36/// let code = GeneratedCode {
37///     files: vec![],
38/// };
39///
40/// assert_eq!(code.file_count(), 0);
41/// ```
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct GeneratedCode {
44    /// List of generated files with paths and contents
45    pub files: Vec<GeneratedFile>,
46}
47
48impl GeneratedCode {
49    /// Creates a new empty generated code container.
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// use mcp_execution_codegen::GeneratedCode;
55    ///
56    /// let code = GeneratedCode::new();
57    /// assert_eq!(code.file_count(), 0);
58    /// ```
59    #[inline]
60    #[must_use]
61    pub fn new() -> Self {
62        Self { files: Vec::new() }
63    }
64
65    /// Adds a generated file to the collection.
66    ///
67    /// # Examples
68    ///
69    /// ```
70    /// use mcp_execution_codegen::{GeneratedCode, GeneratedFile};
71    ///
72    /// let mut code = GeneratedCode::new();
73    /// code.add_file(GeneratedFile {
74    ///     path: "index.ts".to_string(),
75    ///     content: "export {}".to_string(),
76    /// });
77    ///
78    /// assert_eq!(code.file_count(), 1);
79    /// ```
80    pub fn add_file(&mut self, file: GeneratedFile) {
81        self.files.push(file);
82    }
83
84    /// Returns the number of generated files.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use mcp_execution_codegen::GeneratedCode;
90    ///
91    /// let code = GeneratedCode::new();
92    /// assert_eq!(code.file_count(), 0);
93    /// ```
94    #[inline]
95    #[must_use]
96    pub fn file_count(&self) -> usize {
97        self.files.len()
98    }
99
100    /// Returns an iterator over the generated files.
101    ///
102    /// # Examples
103    ///
104    /// ```
105    /// use mcp_execution_codegen::{GeneratedCode, GeneratedFile};
106    ///
107    /// let mut code = GeneratedCode::new();
108    /// code.add_file(GeneratedFile {
109    ///     path: "test.ts".to_string(),
110    ///     content: "content".to_string(),
111    /// });
112    ///
113    /// for file in code.files() {
114    ///     println!("Path: {}", file.path);
115    /// }
116    /// ```
117    #[inline]
118    pub fn files(&self) -> impl Iterator<Item = &GeneratedFile> {
119        self.files.iter()
120    }
121}
122
123impl Default for GeneratedCode {
124    fn default() -> Self {
125        Self::new()
126    }
127}
128
129/// A single generated file with path and content.
130///
131/// Represents one file that will be written to the virtual filesystem
132/// or actual filesystem during code generation.
133///
134/// # Examples
135///
136/// ```
137/// use mcp_execution_codegen::GeneratedFile;
138///
139/// let file = GeneratedFile {
140///     path: "types.ts".to_string(),
141///     content: "export type Params = {};".to_string(),
142/// };
143///
144/// assert_eq!(file.path, "types.ts");
145/// ```
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct GeneratedFile {
148    /// Relative path where the file should be written
149    pub path: String,
150    /// File content
151    pub content: String,
152}
153
154impl GeneratedFile {
155    /// Returns the file path.
156    ///
157    /// # Examples
158    ///
159    /// ```
160    /// use mcp_execution_codegen::GeneratedFile;
161    ///
162    /// let file = GeneratedFile {
163    ///     path: "test.ts".to_string(),
164    ///     content: String::new(),
165    /// };
166    ///
167    /// assert_eq!(file.path(), "test.ts");
168    /// ```
169    #[inline]
170    #[must_use]
171    pub fn path(&self) -> &str {
172        &self.path
173    }
174
175    /// Returns the file content.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use mcp_execution_codegen::GeneratedFile;
181    ///
182    /// let file = GeneratedFile {
183    ///     path: "test.ts".to_string(),
184    ///     content: "export {}".to_string(),
185    /// };
186    ///
187    /// assert_eq!(file.content(), "export {}");
188    /// ```
189    #[inline]
190    #[must_use]
191    pub fn content(&self) -> &str {
192        &self.content
193    }
194}
195
196/// Template context for code generation.
197///
198/// Contains all the data needed to render a Handlebars template.
199/// This is typically constructed from MCP server information.
200///
201/// # Examples
202///
203/// ```
204/// use mcp_execution_codegen::TemplateContext;
205/// use std::collections::HashMap;
206///
207/// let context = TemplateContext {
208///     server_name: "github".to_string(),
209///     server_version: "1.0.0".to_string(),
210///     tools: vec![],
211///     metadata: HashMap::new(),
212/// };
213///
214/// assert_eq!(context.server_name, "github");
215/// ```
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct TemplateContext {
218    /// Name of the MCP server
219    pub server_name: String,
220    /// Server version string
221    pub server_version: String,
222    /// List of tool definitions
223    pub tools: Vec<ToolDefinition>,
224    /// Additional metadata for template rendering
225    pub metadata: HashMap<String, serde_json::Value>,
226}
227
228/// Definition of a single MCP tool for code generation.
229///
230/// Contains all information needed to generate TypeScript or Rust
231/// code for calling an MCP tool.
232///
233/// # Examples
234///
235/// ```
236/// use mcp_execution_codegen::ToolDefinition;
237/// use serde_json::json;
238///
239/// let tool = ToolDefinition {
240///     name: "send_message".to_string(),
241///     description: "Sends a message".to_string(),
242///     input_schema: json!({"type": "object"}),
243///     typescript_name: "sendMessage".to_string(),
244/// };
245///
246/// assert_eq!(tool.name, "send_message");
247/// assert_eq!(tool.typescript_name, "sendMessage");
248/// ```
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub struct ToolDefinition {
251    /// Original tool name (snake_case from MCP)
252    pub name: String,
253    /// Human-readable description
254    pub description: String,
255    /// JSON Schema for input parameters
256    pub input_schema: serde_json::Value,
257    /// TypeScript-friendly name (camelCase)
258    pub typescript_name: String,
259}
260
261#[cfg(test)]
262mod tests {
263    use super::*;
264
265    #[test]
266    fn test_generated_code_new() {
267        let code = GeneratedCode::new();
268        assert_eq!(code.file_count(), 0);
269    }
270
271    #[test]
272    fn test_generated_code_default() {
273        let code = GeneratedCode::default();
274        assert_eq!(code.file_count(), 0);
275    }
276
277    #[test]
278    fn test_add_file() {
279        let mut code = GeneratedCode::new();
280        code.add_file(GeneratedFile {
281            path: "test.ts".to_string(),
282            content: "content".to_string(),
283        });
284        assert_eq!(code.file_count(), 1);
285    }
286
287    #[test]
288    fn test_tool_definition() {
289        let tool = ToolDefinition {
290            name: "test_tool".to_string(),
291            description: "Test".to_string(),
292            input_schema: serde_json::json!({"type": "object"}),
293            typescript_name: "testTool".to_string(),
294        };
295
296        assert_eq!(tool.name, "test_tool");
297        assert_eq!(tool.typescript_name, "testTool");
298    }
299
300    #[test]
301    fn test_template_context() {
302        let context = TemplateContext {
303            server_name: "test-server".to_string(),
304            server_version: "1.0.0".to_string(),
305            tools: vec![],
306            metadata: HashMap::new(),
307        };
308
309        assert_eq!(context.server_name, "test-server");
310        assert_eq!(context.tools.len(), 0);
311    }
312}