1use crate::formats::parse_custom_format;
2use crate::transformers::custom_format_to_resource;
3
4use langcodec::{Codec, converter};
5
6#[derive(Debug, Clone, PartialEq, clap::ValueEnum)]
8pub enum ConflictStrategy {
9 First,
11 Last,
13 Skip,
15}
16
17pub fn run_merge_command(
19 inputs: Vec<String>,
20 output: String,
21 strategy: ConflictStrategy,
22 lang: Option<String>,
23) {
24 if inputs.is_empty() {
25 eprintln!("Error: At least one input file is required.");
26 std::process::exit(1);
27 }
28
29 let mut codec = Codec::new();
31 for (i, input) in inputs.iter().enumerate() {
32 println!("Reading file {}/{}: {}", i + 1, inputs.len(), input);
33
34 if let Ok(()) = codec.read_file_by_extension(input, lang.clone()) {
36 continue;
37 }
38
39 if input.ends_with(".json") || input.ends_with(".yaml") || input.ends_with(".yml") {
41 if let Ok(()) = try_custom_format_merge(input, lang.clone(), &mut codec) {
42 continue;
43 }
44 }
45
46 println!("❌ Error reading input file");
48 eprintln!("Error reading {}: unsupported format", input);
49 std::process::exit(1);
50 }
51
52 println!("Merging resources...");
56 let conflict_strategy = match strategy {
57 ConflictStrategy::First => langcodec::types::ConflictStrategy::First,
58 ConflictStrategy::Last => langcodec::types::ConflictStrategy::Last,
59 ConflictStrategy::Skip => langcodec::types::ConflictStrategy::Skip,
60 };
61
62 let merge_count = codec.merge_resources(&conflict_strategy);
63 println!("Merged {} language groups", merge_count);
64
65 println!("Writing merged output...");
66 match converter::infer_format_from_path(output.clone()) {
67 Some(format) => {
68 println!("Converting resources to format: {:?}", format);
69 if let Err(e) = converter::convert_resources_to_format(codec.resources, &output, format)
70 {
71 println!("❌ Error converting resources to format");
72 eprintln!("Error converting to {}: {}", output, e);
73 std::process::exit(1);
74 }
75 }
76 None => {
77 if codec.resources.len() == 1 {
78 println!("Writing single resource to output file");
79 if let Some(resource) = codec.resources.first() {
80 if let Err(e) = Codec::write_resource_to_file(resource, &output) {
81 println!("❌ Error writing output file");
82 eprintln!("Error writing to {}: {}", output, e);
83 std::process::exit(1);
84 }
85 }
86 } else {
87 println!("❌ Error writing output file");
88 eprintln!("Error writing to {}: multiple resources", output);
89 std::process::exit(1);
90 }
91 }
92 }
93
94 println!(
95 "✅ Successfully merged {} files into {}",
96 inputs.len(),
97 output
98 );
99}
100
101fn try_custom_format_merge(
103 input: &str,
104 _lang: Option<String>,
105 codec: &mut Codec,
106) -> Result<(), String> {
107 crate::validation::validate_custom_format_file(input)?;
109
110 let file_content = std::fs::read_to_string(input)
112 .map_err(|e| format!("Error reading file {}: {}", input, e))?;
113
114 crate::formats::validate_custom_format_content(input, &file_content)?;
116
117 let resources =
119 custom_format_to_resource(input.to_string(), parse_custom_format("json-language-map")?)?;
120
121 for resource in resources {
123 codec.add_resource(resource);
124 }
125
126 Ok(())
127}