node-project-gen 0.0.4

⚡ Blazing fast, architecture-aware Node.js backend generator. Scaffold production-ready projects in under 1 second.
use crate::cli::*;
use crate::generator::ProjectConfig;
use std::path::PathBuf;

pub fn generate(
    project_path: &PathBuf,
    config: &ProjectConfig,
) -> Result<(), Box<dyn std::error::Error>> {
    let utils_dir = config.get_utils_dir();
    std::fs::create_dir_all(project_path.join(&utils_dir))?;

    generate_logger(project_path, config, &utils_dir)?;
    generate_response_helper(project_path, config, &utils_dir)?;
    Ok(())
}

fn generate_logger(
    project_path: &PathBuf,
    config: &ProjectConfig,
    utils_dir: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let ext = config.get_ext();
    let config_import = config.get_config_import_path();

    let content = match config.logger {
        LoggerLib::Winston => {
            format!(
                r#"import winston from 'winston';
import {{ config }} from '{config_import}';

const consoleFormat = winston.format.combine(
  winston.format.colorize(),
  winston.format.timestamp({{ format: 'HH:mm:ss' }}),
  winston.format.printf(({{ timestamp, level, message }}) => {{
    return `${{timestamp}} [${{level}}]: ${{message}}`;
  }}),
);

export const logger = winston.createLogger({{
  level: config.logLevel,
  format: winston.format.json(),
  transports: [
    new winston.transports.Console({{
      format: config.nodeEnv === 'development' ? consoleFormat : winston.format.json(),
    }}),
  ],
}});
"#,
                config_import = config_import
            )
        }
        LoggerLib::Pino => {
            format!(
                r#"import pino from 'pino';
import {{ config }} from '{config_import}';

export const logger = pino({{
  level: config.logLevel,
  ...(config.nodeEnv === 'development' ? {{
    transport: {{ target: 'pino-pretty', options: {{ colorize: true }} }},
  }} : {{}}),
}});
"#,
                config_import = config_import
            )
        }
    };

    std::fs::write(project_path.join(format!("{}/logger.{}", utils_dir, ext)), content)?;
    Ok(())
}

fn generate_response_helper(
    project_path: &PathBuf,
    config: &ProjectConfig,
    utils_dir: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let ext = config.get_ext();

    let content = r#"import { Response } from 'express';

export class ApiResponse {
  static success<T>(res: Response, data: T, message = 'Success', statusCode = 200): void {
    res.status(statusCode).json({ success: true, message, data });
  }

  static created<T>(res: Response, data: T, message = 'Created'): void {
    ApiResponse.success(res, data, message, 201);
  }

  static error(res: Response, message: string, statusCode = 500): void {
    res.status(statusCode).json({ success: false, message });
  }

  static paginated<T>(res: Response, data: T[], total: number, page: number, limit: number): void {
    res.json({
      success: true, data,
      pagination: { page, limit, total, pages: Math.ceil(total / limit) },
    });
  }
}
"#;

    std::fs::write(project_path.join(format!("{}/response.{}", utils_dir, ext)), content)?;
    Ok(())
}