Skip to main content

alef_core/config/resolved/
naming.rs

1//! Language-specific naming methods for `ResolvedCrateConfig`.
2
3use super::ResolvedCrateConfig;
4
5impl ResolvedCrateConfig {
6    /// Get the Python module name.
7    pub fn python_module_name(&self) -> String {
8        self.python
9            .as_ref()
10            .and_then(|p| p.module_name.as_ref())
11            .cloned()
12            .unwrap_or_else(|| format!("_{}", self.name.replace('-', "_")))
13    }
14
15    /// Get the Node package name.
16    pub fn node_package_name(&self) -> String {
17        self.node
18            .as_ref()
19            .and_then(|n| n.package_name.as_ref())
20            .cloned()
21            .unwrap_or_else(|| self.name.clone())
22    }
23
24    /// Get the Ruby gem name.
25    pub fn ruby_gem_name(&self) -> String {
26        self.ruby
27            .as_ref()
28            .and_then(|r| r.gem_name.as_ref())
29            .cloned()
30            .unwrap_or_else(|| self.name.replace('-', "_"))
31    }
32
33    /// Get the PHP extension name.
34    pub fn php_extension_name(&self) -> String {
35        self.php
36            .as_ref()
37            .and_then(|p| p.extension_name.as_ref())
38            .cloned()
39            .unwrap_or_else(|| self.name.replace('-', "_"))
40    }
41
42    /// Get the PHP binding Cargo crate name (used for deriving the shared library filename).
43    pub fn php_cargo_crate_name(&self) -> Option<&str> {
44        self.php.as_ref().and_then(|p| p.cargo_crate_name.as_deref())
45    }
46
47    /// Get the Elixir app name.
48    pub fn elixir_app_name(&self) -> String {
49        self.elixir
50            .as_ref()
51            .and_then(|e| e.app_name.as_ref())
52            .cloned()
53            .unwrap_or_else(|| self.name.replace('-', "_"))
54    }
55
56    /// Get the Zig module name.
57    pub fn zig_module_name(&self) -> String {
58        self.zig
59            .as_ref()
60            .and_then(|z| z.module_name.as_ref())
61            .cloned()
62            .unwrap_or_else(|| self.name.replace('-', "_"))
63    }
64
65    /// Get the Dart pubspec package name.
66    ///
67    /// Returns `[dart] pubspec_name` if set, otherwise derives a snake_case
68    /// name from the crate name by replacing hyphens with underscores.
69    pub fn dart_pubspec_name(&self) -> String {
70        self.dart
71            .as_ref()
72            .and_then(|d| d.pubspec_name.as_ref())
73            .cloned()
74            .unwrap_or_else(|| self.name.replace('-', "_"))
75    }
76
77    /// Get the Dart FRB bridge class name.
78    ///
79    /// Converts `[dart] lib_name` (falling back to `dart_pubspec_name()`) to
80    /// PascalCase and appends `"Bridge"`, matching the FRB v2 convention.
81    /// E.g. `lib_name = "kreuzcrawl"` → `"KreuzcrawlBridge"`.
82    pub fn dart_bridge_class_name(&self) -> String {
83        use heck::ToUpperCamelCase;
84        let lib_name = self
85            .dart
86            .as_ref()
87            .and_then(|d| d.lib_name.as_ref())
88            .cloned()
89            .unwrap_or_else(|| self.dart_pubspec_name());
90        format!("{}Bridge", lib_name.to_upper_camel_case())
91    }
92
93    /// Get the Swift module name.
94    ///
95    /// Returns `[swift] module_name` if configured, otherwise derives a PascalCase
96    /// name from the crate name (e.g. `"my-lib"` → `"MyLib"`).
97    pub fn swift_module(&self) -> String {
98        self.swift
99            .as_ref()
100            .and_then(|s| s.module_name.as_ref())
101            .cloned()
102            .unwrap_or_else(|| {
103                use heck::ToUpperCamelCase;
104                self.name.to_upper_camel_case()
105            })
106    }
107
108    /// Get the R package name.
109    pub fn r_package_name(&self) -> String {
110        self.r
111            .as_ref()
112            .and_then(|r| r.package_name.as_ref())
113            .cloned()
114            .unwrap_or_else(|| self.name.clone())
115    }
116
117    /// Get the WASM type name prefix (e.g. "Wasm" produces `WasmConversionOptions`).
118    /// Defaults to `"Wasm"`.
119    pub fn wasm_type_prefix(&self) -> String {
120        self.wasm
121            .as_ref()
122            .and_then(|w| w.type_prefix.as_ref())
123            .cloned()
124            .unwrap_or_else(|| "Wasm".to_string())
125    }
126
127    /// Get the Node/NAPI type name prefix (e.g. "Js" produces `JsConversionOptions`).
128    /// Defaults to `"Js"`.
129    pub fn node_type_prefix(&self) -> String {
130        self.node
131            .as_ref()
132            .and_then(|n| n.type_prefix.as_ref())
133            .cloned()
134            .unwrap_or_else(|| "Js".to_string())
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use crate::config::new_config::NewAlefConfig;
141
142    fn resolved_one(toml: &str) -> super::super::ResolvedCrateConfig {
143        let cfg: NewAlefConfig = toml::from_str(toml).unwrap();
144        cfg.resolve().unwrap().remove(0)
145    }
146
147    fn minimal() -> super::super::ResolvedCrateConfig {
148        resolved_one(
149            r#"
150[workspace]
151languages = ["python", "node"]
152
153[[crates]]
154name = "test-lib"
155sources = ["src/lib.rs"]
156"#,
157        )
158    }
159
160    #[test]
161    fn python_module_name_defaults_to_underscore_prefix() {
162        let r = minimal();
163        assert_eq!(r.python_module_name(), "_test_lib");
164    }
165
166    #[test]
167    fn python_module_name_explicit_override() {
168        let r = resolved_one(
169            r#"
170[workspace]
171languages = ["python"]
172
173[[crates]]
174name = "test-lib"
175sources = ["src/lib.rs"]
176
177[crates.python]
178module_name = "mymod"
179"#,
180        );
181        assert_eq!(r.python_module_name(), "mymod");
182    }
183
184    #[test]
185    fn node_package_name_defaults_to_crate_name() {
186        let r = minimal();
187        assert_eq!(r.node_package_name(), "test-lib");
188    }
189
190    #[test]
191    fn ruby_gem_name_replaces_hyphens() {
192        let r = minimal();
193        assert_eq!(r.ruby_gem_name(), "test_lib");
194    }
195
196    #[test]
197    fn php_extension_name_replaces_hyphens() {
198        let r = minimal();
199        assert_eq!(r.php_extension_name(), "test_lib");
200    }
201
202    #[test]
203    fn elixir_app_name_replaces_hyphens() {
204        let r = minimal();
205        assert_eq!(r.elixir_app_name(), "test_lib");
206    }
207
208    #[test]
209    fn zig_module_name_replaces_hyphens() {
210        let r = minimal();
211        assert_eq!(r.zig_module_name(), "test_lib");
212    }
213
214    #[test]
215    fn dart_pubspec_name_replaces_hyphens() {
216        let r = minimal();
217        assert_eq!(r.dart_pubspec_name(), "test_lib");
218    }
219
220    #[test]
221    fn swift_module_is_pascal_case() {
222        let r = minimal();
223        assert_eq!(r.swift_module(), "TestLib");
224    }
225
226    #[test]
227    fn r_package_name_defaults_to_crate_name() {
228        let r = minimal();
229        assert_eq!(r.r_package_name(), "test-lib");
230    }
231
232    #[test]
233    fn wasm_type_prefix_defaults_to_wasm() {
234        let r = minimal();
235        assert_eq!(r.wasm_type_prefix(), "Wasm");
236    }
237
238    #[test]
239    fn node_type_prefix_defaults_to_js() {
240        let r = minimal();
241        assert_eq!(r.node_type_prefix(), "Js");
242    }
243}