allframe_forge/templates/
basic.rs

1//! Template strings for project scaffolding
2//!
3//! This module contains all the template strings used when generating
4//! new AllFrame projects with the `allframe ignite` command.
5//!
6//! All templates follow Clean Architecture principles and include:
7//! - Example code demonstrating proper layer separation
8//! - Documentation comments explaining each layer's purpose
9//! - Trait-based abstractions for dependency inversion
10
11/// Generate Cargo.toml content for a new AllFrame project
12///
13/// Creates a minimal `Cargo.toml` with:
14/// - Project name and metadata
15/// - Core dependencies: tokio, serde, anyhow, async-trait
16/// - Binary configuration
17///
18/// Note: The `allframe` crate dependency will be added once it's published to
19/// crates.io.
20///
21/// # Arguments
22/// * `project_name` - Name of the project (used for package name and binary
23///   name)
24///
25/// # Returns
26/// A formatted Cargo.toml file content as a String
27pub fn cargo_toml(project_name: &str) -> String {
28    // For now, we generate a minimal Cargo.toml without allframe dependency
29    // since allframe is not published to crates.io yet.
30    // When allframe is published, we'll add the features and allframe dependency.
31    format!(
32        r#"[package]
33name = "{}"
34version = "0.1.0"
35edition = "2021"
36
37[dependencies]
38tokio = {{ version = "1", features = ["full"] }}
39serde = {{ version = "1", features = ["derive"] }}
40anyhow = "1.0"
41async-trait = "0.1"
42
43[[bin]]
44name = "{}"
45path = "src/main.rs"
46"#,
47        project_name, project_name
48    )
49}
50
51/// Generate src/main.rs content with tokio runtime
52///
53/// Creates the application entry point with:
54/// - Module declarations for all Clean Architecture layers
55/// - Async main function with tokio runtime
56/// - Working example demonstrating layer connections
57///
58/// # Returns
59/// A static string containing the main.rs template
60pub fn main_rs() -> &'static str {
61    r#"//! AllFrame Application
62//!
63//! This is an AllFrame application following Clean Architecture principles.
64
65mod application;
66mod domain;
67mod infrastructure;
68mod presentation;
69
70use application::GreetingService;
71use infrastructure::ConsoleGreeter;
72
73#[tokio::main]
74async fn main() {
75    println!("AllFrame - One frame. Infinite transformations.");
76    println!();
77
78    // Wire up dependencies (Dependency Injection)
79    let greeter = ConsoleGreeter;
80    let service = GreetingService::new(greeter);
81
82    // Execute use case
83    service.greet("World").await;
84
85    println!();
86    println!("Your application is ready!");
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use domain::Greeter;
93
94    struct MockGreeter {
95        messages: std::cell::RefCell<Vec<String>>,
96    }
97
98    impl MockGreeter {
99        fn new() -> Self {
100            Self {
101                messages: std::cell::RefCell::new(Vec::new()),
102            }
103        }
104
105        fn get_messages(&self) -> Vec<String> {
106            self.messages.borrow().clone()
107        }
108    }
109
110    impl Greeter for MockGreeter {
111        fn greet(&self, name: &str) {
112            self.messages.borrow_mut().push(format!("Hello, {}!", name));
113        }
114    }
115
116    #[tokio::test]
117    async fn test_greeting_service() {
118        let greeter = MockGreeter::new();
119        let service = GreetingService::new(greeter);
120
121        service.greet("Test").await;
122
123        // Verify the greeter was called correctly
124        // In a real test, you'd check the mock's recorded calls
125    }
126
127    #[test]
128    fn test_mock_greeter() {
129        let greeter = MockGreeter::new();
130        greeter.greet("Alice");
131        greeter.greet("Bob");
132
133        let messages = greeter.get_messages();
134        assert_eq!(messages.len(), 2);
135        assert_eq!(messages[0], "Hello, Alice!");
136        assert_eq!(messages[1], "Hello, Bob!");
137    }
138}
139"#
140}
141
142/// Generate domain/mod.rs content
143pub fn domain_mod() -> &'static str {
144    r#"//! Domain Layer
145//!
146//! This layer contains the core business logic and has NO external dependencies.
147//!
148//! Structure:
149//! - entities/: Business entities with behavior
150//! - repositories/: Repository trait definitions (interfaces)
151//! - services/: Domain services for complex business logic
152//! - value_objects/: Immutable value types
153
154mod greeter;
155
156pub use greeter::Greeter;
157"#
158}
159
160/// Generate domain/greeter.rs content (replaces entities.rs)
161pub fn domain_greeter() -> &'static str {
162    r#"//! Greeter Domain Trait
163//!
164//! This trait defines the contract for greeting functionality.
165//! Implementations live in the infrastructure layer.
166
167/// A trait for greeting functionality.
168///
169/// This is a domain-level abstraction that allows different
170/// implementations (console, HTTP, mock for testing, etc.)
171pub trait Greeter {
172    /// Greet someone by name.
173    fn greet(&self, name: &str);
174}
175"#
176}
177
178/// Generate application/mod.rs content
179pub fn application_mod() -> &'static str {
180    r#"//! Application Layer
181//!
182//! This layer orchestrates domain objects to fulfill use cases.
183//! It depends only on the domain layer.
184
185mod greeting_service;
186
187pub use greeting_service::GreetingService;
188"#
189}
190
191/// Generate application/greeting_service.rs content
192pub fn application_greeting_service() -> &'static str {
193    r#"//! Greeting Service
194//!
195//! Application service that orchestrates the greeting use case.
196
197use crate::domain::Greeter;
198
199/// Service for greeting users.
200///
201/// This service demonstrates dependency injection - it accepts
202/// any implementation of the Greeter trait.
203pub struct GreetingService<G: Greeter> {
204    greeter: G,
205}
206
207impl<G: Greeter> GreetingService<G> {
208    /// Create a new GreetingService with the given greeter implementation.
209    pub fn new(greeter: G) -> Self {
210        Self { greeter }
211    }
212
213    /// Greet someone by name.
214    pub async fn greet(&self, name: &str) {
215        self.greeter.greet(name);
216    }
217}
218"#
219}
220
221/// Generate infrastructure/mod.rs content
222pub fn infrastructure_mod() -> &'static str {
223    r#"//! Infrastructure Layer
224//!
225//! This layer implements domain traits and handles external concerns.
226//! It depends on the domain layer (implements traits defined there).
227
228mod console_greeter;
229
230pub use console_greeter::ConsoleGreeter;
231"#
232}
233
234/// Generate infrastructure/console_greeter.rs content
235pub fn infrastructure_console_greeter() -> &'static str {
236    r#"//! Console Greeter Implementation
237//!
238//! A concrete implementation of the Greeter trait that prints to the console.
239
240use crate::domain::Greeter;
241
242/// A greeter that prints greetings to the console.
243pub struct ConsoleGreeter;
244
245impl Greeter for ConsoleGreeter {
246    fn greet(&self, name: &str) {
247        println!("Hello, {}!", name);
248    }
249}
250"#
251}
252
253/// Generate presentation/mod.rs content
254pub fn presentation_mod() -> &'static str {
255    r#"//! Presentation Layer
256//!
257//! This layer handles HTTP/gRPC/GraphQL requests and responses.
258//! It depends on the application and domain layers.
259//!
260//! Add your HTTP handlers, GraphQL resolvers, or gRPC services here.
261//! Example:
262//!
263//! ```ignore
264//! mod handlers;
265//! pub use handlers::*;
266//! ```
267"#
268}
269
270/// Generate .gitignore content
271pub fn gitignore() -> &'static str {
272    r#"# Rust
273target/
274Cargo.lock
275
276# IDE
277.vscode/
278.idea/
279*.swp
280*.swo
281
282# OS
283.DS_Store
284Thumbs.db
285
286# Environment
287.env
288.env.local
289
290# Logs
291*.log
292"#
293}
294
295/// Generate README.md content for the project
296///
297/// Creates comprehensive project documentation including:
298/// - Quick start guide
299/// - Project structure explanation
300/// - Feature highlights
301///
302/// # Arguments
303/// * `project_name` - Name of the project (used in title)
304///
305/// # Returns
306/// A formatted README.md file content as a String
307pub fn readme(project_name: &str) -> String {
308    format!(
309        r#"# {}
310
311An AllFrame application following Clean Architecture principles.
312
313## Quick Start
314
315```bash
316# Run the application
317cargo run
318
319# Run tests
320cargo test
321
322# Run with all features
323cargo run --all-features
324```
325
326## Structure
327
328This project follows Clean Architecture:
329
330```
331src/
332├── domain/          # Core business logic (no external dependencies)
333├── application/     # Use case orchestration
334├── infrastructure/  # External implementations (database, HTTP clients)
335└── presentation/    # HTTP/gRPC/GraphQL handlers
336```
337
338## Features
339
340- Clean Architecture enforced
341- TDD-first development
342- Protocol-agnostic (REST/GraphQL/gRPC)
343
344## Built with AllFrame
345
346[AllFrame](https://github.com/all-source-os/all-frame) - The composable Rust API framework.
347
348*One frame. Infinite transformations.*
349"#,
350        project_name
351    )
352}