Skip to main content

es_fluent_cli_helpers/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod cli;
4mod generate;
5
6use es_fluent_derive_core::{EsFluentError, write_metadata_result};
7use es_fluent_toml::I18nConfig;
8use std::path::Path;
9
10pub use cli::{ExpectedKey, InventoryData, write_inventory_for_crate};
11pub use generate::{EsFluentGenerator, FluentParseMode, GeneratorArgs};
12
13/// Type alias for compatibility
14pub type GeneratorError = EsFluentError;
15
16/// Run the FTL generation process for a crate.
17///
18/// This function:
19/// - Reads the i18n.toml configuration
20/// - Resolves output and assets paths
21/// - Runs the es-fluent generator
22/// - Writes the result status to result.json
23///
24/// Returns `true` if any FTL files were modified, `false` otherwise.
25pub fn run_generate(i18n_toml_path: &str, crate_name: &str) -> bool {
26    // Read config from parent crate's i18n.toml
27    let i18n_toml_path = Path::new(i18n_toml_path);
28    let i18n_dir = i18n_toml_path
29        .parent()
30        .expect("Failed to get i18n directory");
31    let config =
32        es_fluent_toml::I18nConfig::from_manifest_dir(i18n_dir).expect("Failed to read i18n.toml");
33    let output_path = I18nConfig::output_dir_from_manifest_dir(i18n_dir)
34        .expect("Failed to resolve output directory");
35    let assets_dir = config
36        .assets_dir_from_base(Some(i18n_dir))
37        .expect("Failed to resolve assets directory");
38
39    let changed = EsFluentGenerator::builder()
40        .output_path(output_path)
41        .assets_dir(assets_dir)
42        .manifest_dir(i18n_dir)
43        .crate_name(crate_name)
44        .build()
45        .run_cli()
46        .expect("Failed to run generator");
47
48    // Write result to JSON file for CLI to read
49    let result = serde_json::json!({ "changed": changed });
50    write_metadata_result(crate_name, &result).expect("Failed to write metadata result");
51    changed
52}
53
54/// Run the FTL generation process with explicit options (no CLI parsing).
55///
56/// This is used by the monolithic binary to avoid conflicting clap argument parsing.
57pub fn run_generate_with_options(
58    i18n_toml_path: &str,
59    crate_name: &str,
60    mode: FluentParseMode,
61    dry_run: bool,
62) -> bool {
63    let i18n_toml_path = Path::new(i18n_toml_path);
64    let i18n_dir = i18n_toml_path
65        .parent()
66        .expect("Failed to get i18n directory");
67    let _config =
68        es_fluent_toml::I18nConfig::from_manifest_dir(i18n_dir).expect("Failed to read i18n.toml");
69    let output_path = I18nConfig::output_dir_from_manifest_dir(i18n_dir)
70        .expect("Failed to resolve output directory");
71
72    let changed = EsFluentGenerator::builder()
73        .output_path(output_path)
74        .assets_dir(
75            I18nConfig::assets_dir_from_manifest_dir(i18n_dir)
76                .expect("Failed to resolve assets directory"),
77        )
78        .manifest_dir(i18n_dir)
79        .crate_name(crate_name)
80        .mode(mode)
81        .dry_run(dry_run)
82        .build()
83        .generate()
84        .expect("Failed to run generator");
85
86    let result = serde_json::json!({ "changed": changed });
87    write_metadata_result(crate_name, &result).expect("Failed to write metadata result");
88    changed
89}
90
91/// Run the inventory check process for a crate.
92///
93/// This writes the collected inventory data for the specified crate.
94pub fn run_check(crate_name: &str) {
95    write_inventory_for_crate(crate_name);
96}
97
98/// Run the FTL clean process with explicit options (no CLI parsing).
99///
100/// This is used by the monolithic binary to avoid conflicting clap argument parsing.
101pub fn run_clean_with_options(
102    i18n_toml_path: &str,
103    crate_name: &str,
104    all_locales: bool,
105    dry_run: bool,
106) -> bool {
107    let i18n_toml_path = Path::new(i18n_toml_path);
108    let i18n_dir = i18n_toml_path
109        .parent()
110        .expect("Failed to get i18n directory");
111    let config =
112        es_fluent_toml::I18nConfig::from_manifest_dir(i18n_dir).expect("Failed to read i18n.toml");
113    let output_path = I18nConfig::output_dir_from_manifest_dir(i18n_dir)
114        .expect("Failed to resolve output directory");
115    let assets_dir = config
116        .assets_dir_from_base(Some(i18n_dir))
117        .expect("Failed to resolve assets directory");
118
119    let changed = EsFluentGenerator::builder()
120        .output_path(output_path)
121        .assets_dir(assets_dir)
122        .manifest_dir(i18n_dir)
123        .crate_name(crate_name)
124        .dry_run(dry_run)
125        .build()
126        .clean(all_locales, dry_run)
127        .expect("Failed to run clean");
128
129    let result = serde_json::json!({ "changed": changed });
130    write_metadata_result(crate_name, &result).expect("Failed to write metadata result");
131    changed
132}
133
134/// Main entry point for the monolithic binary.
135///
136/// Parses command-line arguments and dispatches to the appropriate handler.
137/// This minimizes the code needed in the generated binary template.
138pub fn run() {
139    let args: Vec<String> = std::env::args().collect();
140
141    let command = args.get(1).map(|s| s.as_str()).unwrap_or("check");
142    let i18n_path = args.get(2).map(|s| s.as_str());
143
144    let target_crate = args
145        .iter()
146        .position(|s| s == "--crate")
147        .and_then(|i| args.get(i + 1))
148        .map(|s| s.as_str());
149
150    let mode_str = args
151        .iter()
152        .position(|s| s == "--mode")
153        .and_then(|i| args.get(i + 1))
154        .map(|s| s.as_str())
155        .unwrap_or("conservative");
156
157    let dry_run = args.iter().any(|s| s == "--dry-run");
158    let all_locales = args.iter().any(|s| s == "--all");
159
160    match command {
161        "generate" => {
162            let path = i18n_path.expect("Missing i18n.toml path");
163            let name = target_crate.expect("Missing --crate argument");
164            let mode = match mode_str {
165                "aggressive" => FluentParseMode::Aggressive,
166                _ => FluentParseMode::Conservative,
167            };
168            run_generate_with_options(path, name, mode, dry_run);
169        },
170        "clean" => {
171            let path = i18n_path.expect("Missing i18n.toml path");
172            let name = target_crate.expect("Missing --crate argument");
173            run_clean_with_options(path, name, all_locales, dry_run);
174        },
175        "check" => {
176            let name = target_crate.expect("Missing --crate argument");
177            run_check(name);
178        },
179        _ => {
180            eprintln!("Unknown command: {}", command);
181            std::process::exit(1);
182        },
183    }
184}