cargo-plot 0.3.0-beta.2

Szwajcarski scyzoryk do wizualizacji struktury projektu i generowania dokumentacji bezpośrednio z poziomu Cargo.
Documentation
use crate::lib::logic::{ConfigJob, ConfigManifest, IoConfig, JobEngine, JobMode, JobSpec, MX, RenderFlags};
/// Orchestrator zadań wsadowych.
/// Pobiera konfigurację z plików TOML, tłumaczy ją na silnie typowane obiekty
/// JobSpec i zleca ich wykonanie do rdzennego JobEngine.
pub struct DocEngineMultiple {
	pub manifest: ConfigManifest,
}

impl DocEngineMultiple {
	// ============================================================================
	// LOADERY (Odczyt konfiguracji za pomocą IoConfig)
	// ============================================================================

	/// Wczytuje konfigurację z domyślnego pliku (np. ./.x-do.toml)
	pub fn loader_default() -> Result<Self, String> {
		let manifest = IoConfig::default_config_loader()?;
		Ok(Self { manifest })
	}

	/// Wczytuje konfigurację ze wskazanej ścieżki
	pub fn loader_from_toml(path: &str) -> Result<Self, String> {
		let manifest = IoConfig::config_loader_from(path)?;
		Ok(Self { manifest })
	}

	// ============================================================================
	// PARSERY (Tłumaczenie ConfigJob z TOML na nasz domenowy JobSpec)
	// ============================================================================

	/// Parsuje pojedynczy surowy obiekt konfiguracji TOML na silnie typowany
	/// JobSpec
	pub fn parse(&self, cfg: &ConfigJob) -> Result<JobSpec, String> { JobSpec::from_config(cfg) }

	/// Szuka zadania po ID i parsuje je do JobSpec (nie wykonując go)
	pub fn parse_for(&self, id: &str) -> Result<JobSpec, String> {
		let cfg_job = self
			.manifest
			.job
			.iter()
			.find(|j| j.id == id)
			.ok_or_else(|| format!("❌ Nie znaleziono zadania o ID: '{}'", id))?;

		JobSpec::from_config(cfg_job)
	}

	// ============================================================================
	// EXECUTORY (Wykonywanie zadań za pomocą JobEngine)
	// ============================================================================

	/// Mapuje i wykonuje w pętli wszystkie zadania zdefiniowane w pliku TOML
	pub fn jobs(&self) -> Result<(), String> {
		for cfg_job in &self.manifest.job {
			let spec = self.parse(cfg_job)?;
			self.execute_spec(spec)?;
		}
		Ok(())
	}

	/// Wyszukuje zadanie po ID, mapuje na JobSpec i wykonuje je
	pub fn job_id(&self, id: &str) -> Result<(), String> {
		let spec = self.parse_for(id)?;
		self.execute_spec(spec)?;
		Ok(())
	}

	// ============================================================================
	// SILNIK WYKONAWCZY (Delegacja do JobEngine)
	// ============================================================================

	/// Bierze gotowy i bezpieczny JobSpec, a następnie karmi nim JobEngine
	fn execute_spec(&self, spec: JobSpec) -> Result<(), String> {
		if !spec.quiet_work {
			let name = spec.name.as_deref().unwrap_or("Brak nazwy");
			println!("🚀 Uruchamianie zadania: {} ({})", spec.id, name);
		}

		// 1. Przekładamy JobMode na stare MX dla silnika renderującego
		let mx_mode = match spec.mode {
			JobMode::Matched => MX::Matched,
			JobMode::Mismatched => MX::Mismatched,
		};

		// 2. Inicjujemy rdzewny JobEngine przekazując mu od razu obiekt ScanSpec i
		//    TabSpec
		let mut engine = JobEngine::new(spec.scan.clone()).spec(spec.table.clone());

		// 3. Widok w terminalu (lub cichy stan dla plików)
		if !spec.quiet_work {
			if let Some(size) = spec.table.trim_size {
				let page = Some(spec.table.trim_page);
				engine = engine.view_trimmed(mx_mode, spec.hide_stats, spec.hide_promo, size, page);
			} else {
				engine = engine.view(mx_mode, spec.hide_stats, spec.hide_promo);
			}
		} else {
			// Nawet w trybie cichym zapisujemy konfigurację renderowania na wypadek zapisu
			// do pliku
			engine.last_render =
				Some(RenderFlags { hide_stats: spec.hide_stats, hide_promo: spec.hide_promo, mode: mx_mode });
		}

		// 4. Eksport do plików (niezależnie od trybu quiet)
		if let Some(sotc_path) = &spec.save_sotc_at {
			engine = engine.save_structure_of_the_content(sotc_path, spec.title_sotc.as_deref());
		}
		if let Some(cots_path) = &spec.save_cots_at {
			engine = engine.save_content_of_the_structure(cots_path, spec.title_cots.as_deref());
		}

		let _ = engine;

		if !spec.quiet_work {
			println!("✨ Ukończono zadanie: {}", spec.id);
		}

		Ok(())
	}
}