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        .crate_name(crate_name)
43        .build()
44        .run_cli()
45        .expect("Failed to run generator");
46
47    // Write result to JSON file for CLI to read
48    let result = serde_json::json!({ "changed": changed });
49    write_metadata_result(crate_name, &result).expect("Failed to write metadata result");
50    changed
51}
52
53/// Run the FTL generation process with explicit options (no CLI parsing).
54///
55/// This is used by the monolithic binary to avoid conflicting clap argument parsing.
56pub fn run_generate_with_options(
57    i18n_toml_path: &str,
58    crate_name: &str,
59    mode: FluentParseMode,
60    dry_run: bool,
61) -> bool {
62    let i18n_toml_path = Path::new(i18n_toml_path);
63    let i18n_dir = i18n_toml_path
64        .parent()
65        .expect("Failed to get i18n directory");
66    let _config =
67        es_fluent_toml::I18nConfig::from_manifest_dir(i18n_dir).expect("Failed to read i18n.toml");
68    let output_path = I18nConfig::output_dir_from_manifest_dir(i18n_dir)
69        .expect("Failed to resolve output directory");
70
71    let changed = EsFluentGenerator::builder()
72        .output_path(output_path)
73        .assets_dir(
74            I18nConfig::assets_dir_from_manifest_dir(i18n_dir)
75                .expect("Failed to resolve assets directory"),
76        )
77        .crate_name(crate_name)
78        .mode(mode)
79        .dry_run(dry_run)
80        .build()
81        .generate()
82        .expect("Failed to run generator");
83
84    let result = serde_json::json!({ "changed": changed });
85    write_metadata_result(crate_name, &result).expect("Failed to write metadata result");
86    changed
87}
88
89/// Run the inventory check process for a crate.
90///
91/// This writes the collected inventory data for the specified crate.
92pub fn run_check(crate_name: &str) {
93    write_inventory_for_crate(crate_name);
94}
95
96/// Run the FTL clean process with explicit options (no CLI parsing).
97///
98/// This is used by the monolithic binary to avoid conflicting clap argument parsing.
99pub fn run_clean_with_options(
100    i18n_toml_path: &str,
101    crate_name: &str,
102    all_locales: bool,
103    dry_run: bool,
104) -> bool {
105    let i18n_toml_path = Path::new(i18n_toml_path);
106    let i18n_dir = i18n_toml_path
107        .parent()
108        .expect("Failed to get i18n directory");
109    let config =
110        es_fluent_toml::I18nConfig::from_manifest_dir(i18n_dir).expect("Failed to read i18n.toml");
111    let output_path = I18nConfig::output_dir_from_manifest_dir(i18n_dir)
112        .expect("Failed to resolve output directory");
113    let assets_dir = config
114        .assets_dir_from_base(Some(i18n_dir))
115        .expect("Failed to resolve assets directory");
116
117    let changed = EsFluentGenerator::builder()
118        .output_path(output_path)
119        .assets_dir(assets_dir)
120        .crate_name(crate_name)
121        .dry_run(dry_run)
122        .build()
123        .clean(all_locales, dry_run)
124        .expect("Failed to run clean");
125
126    let result = serde_json::json!({ "changed": changed });
127    write_metadata_result(crate_name, &result).expect("Failed to write metadata result");
128    changed
129}
130
131/// Main entry point for the monolithic binary.
132///
133/// Parses command-line arguments and dispatches to the appropriate handler.
134/// This minimizes the code needed in the generated binary template.
135pub fn run() {
136    let args: Vec<String> = std::env::args().collect();
137
138    let command = args.get(1).map(|s| s.as_str()).unwrap_or("check");
139    let i18n_path = args.get(2).map(|s| s.as_str());
140
141    let target_crate = args
142        .iter()
143        .position(|s| s == "--crate")
144        .and_then(|i| args.get(i + 1))
145        .map(|s| s.as_str());
146
147    let mode_str = args
148        .iter()
149        .position(|s| s == "--mode")
150        .and_then(|i| args.get(i + 1))
151        .map(|s| s.as_str())
152        .unwrap_or("conservative");
153
154    let dry_run = args.iter().any(|s| s == "--dry-run");
155    let all_locales = args.iter().any(|s| s == "--all");
156
157    match command {
158        "generate" => {
159            let path = i18n_path.expect("Missing i18n.toml path");
160            let name = target_crate.expect("Missing --crate argument");
161            let mode = match mode_str {
162                "aggressive" => FluentParseMode::Aggressive,
163                _ => FluentParseMode::Conservative,
164            };
165            run_generate_with_options(path, name, mode, dry_run);
166        },
167        "clean" => {
168            let path = i18n_path.expect("Missing i18n.toml path");
169            let name = target_crate.expect("Missing --crate argument");
170            run_clean_with_options(path, name, all_locales, dry_run);
171        },
172        "check" => {
173            let name = target_crate.expect("Missing --crate argument");
174            run_check(name);
175        },
176        _ => {
177            eprintln!("Unknown command: {}", command);
178            std::process::exit(1);
179        },
180    }
181}