duck-template 0.1.9

A cli tool for generating files from a template just with a json file
mod __test__;
use std::{collections::HashMap, fs, path::Path, process};

use crate::{
  config::config_structure::{File, Folder, Source},
  logger::{LogLevel, log},
};

pub fn replace_args(content: &str, args: &HashMap<String, String>, file_args: &[String]) -> String {
  let mut result = content.to_string();

  for key in file_args {
    let trimmed = key.trim_matches(|c: char| c == '{' || c == '}' || c.is_whitespace());
    if let Some(value) = args.get(trimmed) {
      result = result.replace(key, value);
    }
  }

  result
}

pub fn parse_source(path: &Path, root: &Path, ignore: &Vec<String>) -> Source {
  let rel_path = if path.to_string_lossy() == "./" || path.to_string_lossy() == "." {
    path.strip_prefix(root).unwrap_or(path)
  } else {
    path
  };

  let rel_path_str = if rel_path.as_os_str().is_empty() {
    "".to_string()
  } else {
    rel_path.to_string_lossy().to_string()
  };

  // Skip if the relative path (file or folder) is in the ignore list
  if ignore.contains(&rel_path_str) {
    return Source::Skip;
  }

  if path.is_file() {
    let content = fs::read_to_string(path).unwrap_or_else(|_| "".to_string());

    Source::File(File {
      path: rel_path_str,
      content,
      args: Some(vec![]),
    })
  } else if path.is_dir() {
    let mut children = vec![];

    for entry in fs::read_dir(path).expect("Failed to read folder").flatten() {
      let child_path = entry.path();

      // Skip hidden files/folders (optional)
      if let Some(name) = child_path.file_name().and_then(|n| n.to_str())
        && name.starts_with('.')
      {
        continue;
      }

      // Recursively parse child
      let child = parse_source(&child_path, root, ignore);

      // Skip if child was skipped
      if !matches!(child, Source::Skip) {
        children.push(child);
      }
    }

    Source::Folder(Folder {
      path: rel_path_str,
      children,
    })
  } else {
    log(LogLevel::Error, &format!("❌ Invalid path: {:?}", path));
    process::exit(1);
  }
}