Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 118 additions & 18 deletions crates/rohas-codegen/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fs;
use std::path::{Path, PathBuf};

pub fn generate_package_json(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let project_name = extract_project_name(&project_root);

let content = format!(
Expand Down Expand Up @@ -45,7 +45,7 @@ pub fn generate_package_json(_schema: &Schema, output_dir: &Path) -> Result<()>
}

pub fn generate_tsconfig_json(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let content = r#"{
"compilerOptions": {
"target": "ES2022",
Expand Down Expand Up @@ -88,7 +88,7 @@ pub fn generate_tsconfig_json(_schema: &Schema, output_dir: &Path) -> Result<()>
}

pub fn generate_requirements_txt(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let content = r#"# Python dependencies for Rohas project
# Add your project-specific dependencies here

Expand All @@ -102,7 +102,7 @@ typing-extensions>=4.0.0
}

pub fn generate_pyproject_toml(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let project_name = extract_project_name(&project_root);

let content = format!(
Expand Down Expand Up @@ -146,7 +146,7 @@ target-version = "py39"
}

pub fn generate_cargo_toml(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let project_name = extract_project_name(&project_root);

let lib_name = project_name.replace('-', "_");
Expand Down Expand Up @@ -183,7 +183,28 @@ tokio-test = "0.4"
}

pub fn generate_gitignore(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)
.map_err(|e| crate::error::CodegenError::GenerationFailed(format!(
"Failed to get project root from output_dir {}: {}",
output_dir.display(),
e
)))?;

let gitignore_path = project_root.join(".gitignore");

if let Some(parent) = gitignore_path.parent() {
fs::create_dir_all(parent).map_err(|e| {
crate::error::CodegenError::Io(std::io::Error::new(
e.kind(),
format!(
"Failed to create parent directory {} for .gitignore: {}",
parent.display(),
e
)
))
})?;
}

let content = r#"# Dependencies
node_modules/
__pycache__/
Expand Down Expand Up @@ -238,12 +259,22 @@ coverage/
src/generated/
"#;

fs::write(project_root.join(".gitignore"), content)?;
fs::write(&gitignore_path, content)
.map_err(|e| crate::error::CodegenError::Io(std::io::Error::new(
e.kind(),
format!("Failed to write .gitignore to {}: {}", gitignore_path.display(), e)
)))?;
Ok(())
}

pub fn generate_editorconfig(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let editorconfig_path = project_root.join(".editorconfig");

if let Some(parent) = editorconfig_path.parent() {
fs::create_dir_all(parent)?;
}

let content = r#"# EditorConfig is awesome: https://EditorConfig.org

root = true
Expand All @@ -270,12 +301,21 @@ indent_size = 2
trim_trailing_whitespace = false
"#;

fs::write(project_root.join(".editorconfig"), content)?;
fs::write(&editorconfig_path, content)
.map_err(|e| crate::error::CodegenError::Io(std::io::Error::new(
e.kind(),
format!("Failed to write .editorconfig to {}: {}", editorconfig_path.display(), e)
)))?;
Ok(())
}

pub fn generate_readme(schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)
.map_err(|e| crate::error::CodegenError::GenerationFailed(format!(
"Failed to get project root from output_dir {} in generate_readme: {}",
output_dir.display(),
e
)))?;
let project_name = extract_project_name(&project_root);
let has_apis = !schema.apis.is_empty();
let has_events = !schema.events.is_empty();
Expand Down Expand Up @@ -400,22 +440,31 @@ MIT
);

let readme_path = project_root.join("README.md");

if let Some(parent) = readme_path.parent() {
fs::create_dir_all(parent)?;
}

if !readme_path.exists() {
fs::write(readme_path, content)?;
fs::write(&readme_path, content)
.map_err(|e| crate::error::CodegenError::Io(std::io::Error::new(
e.kind(),
format!("Failed to write README.md to {}: {}", readme_path.display(), e)
)))?;
}

Ok(())
}

pub fn generate_nvmrc(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let content = "18.0.0\n";
fs::write(project_root.join(".nvmrc"), content)?;
Ok(())
}

pub fn generate_prettierrc(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let content = r#"{
"semi": true,
"trailingComma": "es5",
Expand All @@ -432,7 +481,7 @@ pub fn generate_prettierrc(_schema: &Schema, output_dir: &Path) -> Result<()> {
}

pub fn generate_prettierignore(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let content = r#"node_modules/
dist/
build/
Expand All @@ -447,7 +496,7 @@ src/generated/
}

pub fn generate_rspack_config(_schema: &Schema, output_dir: &Path) -> Result<()> {
let project_root = get_project_root(output_dir);
let project_root = get_project_root(output_dir)?;
let content = r#"const path = require('path');
const fs = require('fs');

Expand Down Expand Up @@ -548,12 +597,63 @@ module.exports = {
Ok(())
}

fn get_project_root(output_dir: &Path) -> PathBuf {
if output_dir.file_name().and_then(|s| s.to_str()) == Some("src") {
output_dir.parent().unwrap_or(output_dir).to_path_buf()
fn get_project_root(output_dir: &Path) -> Result<PathBuf> {
let project_root = if output_dir.file_name().and_then(|s| s.to_str()) == Some("src") {
match output_dir.parent() {
Some(parent) => {
let parent_path = parent.to_path_buf();
if parent_path.as_os_str().is_empty() || parent_path == Path::new("/") {
output_dir.to_path_buf()
} else {
parent_path
}
}
None => {
return Err(crate::error::CodegenError::GenerationFailed(format!(
"Cannot determine project root from output_dir: {}",
output_dir.display()
)));
}
}
} else {
output_dir.to_path_buf()
};
match fs::metadata(&project_root) {
Ok(metadata) => {
if !metadata.is_dir() {
return Err(crate::error::CodegenError::GenerationFailed(format!(
"Project root path exists but is not a directory: {}",
project_root.display()
)));
}
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
fs::create_dir_all(&project_root).map_err(|e| {
crate::error::CodegenError::Io(std::io::Error::new(
e.kind(),
format!(
"Failed to create project root directory {} (from output_dir {}): {}",
project_root.display(),
output_dir.display(),
e
)
))
})?;
}
Err(e) => {
return Err(crate::error::CodegenError::Io(std::io::Error::new(
e.kind(),
format!(
"Failed to check project root directory {} (from output_dir {}): {}",
project_root.display(),
output_dir.display(),
e
)
)));
}
}

Ok(project_root)
}

fn extract_project_name(project_root: &Path) -> String {
Expand Down
65 changes: 61 additions & 4 deletions crates/rohas-codegen/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ impl Generator {
output_dir.display()
);

if let Some(parent) = output_dir.parent() {
fs::create_dir_all(parent)?;
}
fs::create_dir_all(output_dir)?;

self.create_directory_structure(output_dir)?;

self.generate_common_configs(schema, output_dir)?;
Expand Down Expand Up @@ -64,10 +69,43 @@ impl Generator {
}

fn generate_common_configs(&self, schema: &Schema, output_dir: &Path) -> Result<()> {
use tracing::error;
info!("Generating common configuration files");
config::generate_gitignore(schema, output_dir)?;
config::generate_editorconfig(schema, output_dir)?;
config::generate_readme(schema, output_dir)?;
info!("Output directory: {}", output_dir.display());

info!("Generating .gitignore...");
config::generate_gitignore(schema, output_dir)
.map_err(|e| {
error!("Failed to generate .gitignore: {}", e);
crate::error::CodegenError::GenerationFailed(format!(
"Failed to generate .gitignore: {}",
e
))
})?;
info!("Generated .gitignore successfully");

info!("Generating .editorconfig...");
config::generate_editorconfig(schema, output_dir)
.map_err(|e| {
error!("Failed to generate .editorconfig: {}", e);
crate::error::CodegenError::GenerationFailed(format!(
"Failed to generate .editorconfig: {}",
e
))
})?;
info!("Generated .editorconfig successfully");

info!("Generating README.md...");
config::generate_readme(schema, output_dir)
.map_err(|e| {
error!("Failed to generate README.md: {}", e);
crate::error::CodegenError::GenerationFailed(format!(
"Failed to generate README.md: {}",
e
))
})?;
info!("Generated README.md successfully");

Ok(())
}

Expand Down Expand Up @@ -112,14 +150,33 @@ impl Generator {
}

fn generate_rust(&self, schema: &Schema, output_dir: &Path) -> Result<()> {
use tracing::error;

info!("Generating Rust code...");
info!("Generating state...");
rust::generate_state(output_dir)?;
info!("Generating models...");
rust::generate_models(schema, output_dir)?;
info!("Generating DTOs...");
rust::generate_dtos(schema, output_dir)?;
info!("Generating APIs...");
rust::generate_apis(schema, output_dir)?;
info!("Generating events...");
rust::generate_events(schema, output_dir)?;
info!("Generating crons...");
rust::generate_crons(schema, output_dir)?;
rust::generate_websockets(schema, output_dir)?;
info!("Generating websockets...");
rust::generate_websockets(schema, output_dir)
.map_err(|e| {
error!("Failed to generate websockets: {}", e);
crate::error::CodegenError::GenerationFailed(format!(
"Failed to generate websockets: {}",
e
))
})?;
info!("Generating middlewares...");
rust::generate_middlewares(schema, output_dir)?;
info!("Generating lib.rs...");
rust::generate_lib_rs(schema, output_dir)?;

info!("Generating Rust configuration files");
Expand Down
Loading