From c05584561b6c9f1ac2097275513cf0a542c30317 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Mon, 23 Mar 2026 01:50:50 +0100 Subject: [PATCH] fix(cli): deduplicate formats, pre-validate before writing --- crates/bin/src/cli.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/bin/src/cli.rs b/crates/bin/src/cli.rs index 1282c7a..b4a20c1 100644 --- a/crates/bin/src/cli.rs +++ b/crates/bin/src/cli.rs @@ -1,7 +1,6 @@ use std::{fs, path::PathBuf}; use clap::Parser; -use exporters; use lib::{BlockPalette, OutlineMode, TextBuilder, TtfFont}; #[derive(Parser, Debug)] @@ -144,18 +143,32 @@ pub fn run() -> anyhow::Result<()> { grid.depth ); - let format_names: Vec<&str> = if cli.format.is_empty() { + let all_names = exporters::available_names(); + + let raw_formats: Vec<&str> = if cli.format.is_empty() { vec!["mcfunction"] } else if cli.format.iter().any(|f| f == "all") { - exporters::available_names() + all_names.clone() } else { cli.format.iter().map(String::as_str).collect() }; - for name in format_names { - let exporter = exporters::build(name, &palette) - .ok_or_else(|| anyhow::anyhow!("unknown format '{}'. Available: {}", name, exporters::available_names().join(", ")))?; + // Deduplicate while preserving order + let mut seen = std::collections::HashSet::new(); + let format_names: Vec<&str> = raw_formats + .into_iter() + .filter(|&name| seen.insert(name)) + .collect(); + // Pre-validate all names before writing anything + for name in &format_names { + if exporters::build(name, &palette).is_none() { + anyhow::bail!("unknown format '{}'. Available: {}", name, all_names.join(", ")); + } + } + + for name in format_names { + let exporter = exporters::build(name, &palette).unwrap(); // safe: pre-validated let output_bytes = exporter.export(&grid)?; let mut out_path = cli.out.clone(); out_path.set_extension(exporter.file_extension());