Skip to main content

alef_core/config/
languages.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::path::PathBuf;
4
5use super::extras::Language;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct PythonConfig {
9    pub module_name: Option<String>,
10    pub async_runtime: Option<String>,
11    pub stubs: Option<StubsConfig>,
12    /// PyPI package name (e.g. `"html-to-markdown"`). Used as the `[project] name` in
13    /// `pyproject.toml` and to derive the `python-packages` list for maturin.
14    /// Defaults to the crate name.
15    #[serde(default)]
16    pub pip_name: Option<String>,
17    /// Per-language feature override. When set, these features are used instead of
18    /// `[crate] features` for this language's binding crate.
19    #[serde(default)]
20    pub features: Option<Vec<String>>,
21    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
22    /// When set, this takes priority over the IR type-level serde_rename_all.
23    #[serde(default)]
24    pub serde_rename_all: Option<String>,
25    /// Map of type name -> PyCapsule name for raw pointer wrapping.
26    /// When a function returns one of these types, alef generates PyCapsule_New instead of Arc wrapping.
27    // TODO: Wire into gen_bindings.rs to emit PyCapsule_New / PyCapsule_GetPointer at call sites.
28    #[serde(default)]
29    pub capsule_types: HashMap<String, String>,
30    /// When true, wrap blocking function bodies in py.allow_threads() to release the GIL.
31    // TODO: Wire into gen_bindings.rs to emit py.allow_threads(|| { ... }) for non-async functions.
32    #[serde(default)]
33    pub release_gil: bool,
34    /// Functions to exclude from Python binding generation.
35    #[serde(default)]
36    pub exclude_functions: Vec<String>,
37    /// Types to exclude from Python binding generation.
38    #[serde(default)]
39    pub exclude_types: Vec<String>,
40    /// Additional Cargo dependencies for this language's binding crate only.
41    #[serde(default)]
42    pub extra_dependencies: HashMap<String, toml::Value>,
43    /// Override the scaffold output directory for this language's Cargo.toml and package files.
44    #[serde(default)]
45    pub scaffold_output: Option<PathBuf>,
46    /// Per-field name remapping for this language. Key is `TypeName.field_name` (e.g.
47    /// `"LayoutDetection.class"`), value is the desired binding field name. Applied after
48    /// automatic keyword escaping, so an explicit entry takes priority.
49    #[serde(default)]
50    pub rename_fields: HashMap<String, String>,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct StubsConfig {
55    pub output: PathBuf,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct NodeConfig {
60    pub package_name: Option<String>,
61    /// Per-language feature override. When set, these features are used instead of
62    /// `[crate] features` for this language's binding crate.
63    #[serde(default)]
64    pub features: Option<Vec<String>>,
65    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
66    /// When set, this takes priority over the IR type-level serde_rename_all.
67    #[serde(default)]
68    pub serde_rename_all: Option<String>,
69    /// Prefix for generated type names (e.g. "Js" produces `JsConversionOptions`).
70    /// Defaults to `"Js"`.
71    #[serde(default)]
72    pub type_prefix: Option<String>,
73    /// Functions to exclude from Node binding generation.
74    #[serde(default)]
75    pub exclude_functions: Vec<String>,
76    /// Types to exclude from Node binding generation.
77    #[serde(default)]
78    pub exclude_types: Vec<String>,
79    /// Additional Cargo dependencies for this language's binding crate only.
80    #[serde(default)]
81    pub extra_dependencies: HashMap<String, toml::Value>,
82    /// Override the scaffold output directory for this language's Cargo.toml and package files.
83    #[serde(default)]
84    pub scaffold_output: Option<PathBuf>,
85    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
86    /// desired binding field name. Applied after automatic keyword escaping.
87    #[serde(default)]
88    pub rename_fields: HashMap<String, String>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct RubyConfig {
93    pub gem_name: Option<String>,
94    pub stubs: Option<StubsConfig>,
95    /// Per-language feature override. When set, these features are used instead of
96    /// `[crate] features` for this language's binding crate.
97    #[serde(default)]
98    pub features: Option<Vec<String>>,
99    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
100    /// When set, this takes priority over the IR type-level serde_rename_all.
101    #[serde(default)]
102    pub serde_rename_all: Option<String>,
103    /// Functions to exclude from Ruby binding generation.
104    #[serde(default)]
105    pub exclude_functions: Vec<String>,
106    /// Types to exclude from Ruby binding generation.
107    #[serde(default)]
108    pub exclude_types: Vec<String>,
109    /// Additional Cargo dependencies for this language's binding crate only.
110    #[serde(default)]
111    pub extra_dependencies: HashMap<String, toml::Value>,
112    /// Override the scaffold output directory for this language's Cargo.toml and package files.
113    #[serde(default)]
114    pub scaffold_output: Option<PathBuf>,
115    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
116    /// desired binding field name. Applied after automatic keyword escaping.
117    #[serde(default)]
118    pub rename_fields: HashMap<String, String>,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct PhpConfig {
123    pub extension_name: Option<String>,
124    /// Feature gate for ext-php-rs (default: "extension-module").
125    /// All generated code is wrapped in `#[cfg(feature = "...")]`.
126    #[serde(default)]
127    pub feature_gate: Option<String>,
128    /// Output directory for generated PHP facade / stubs (e.g., `packages/php/src/`).
129    #[serde(default)]
130    pub stubs: Option<StubsConfig>,
131    #[serde(default)]
132    pub features: Option<Vec<String>>,
133    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
134    /// When set, this takes priority over the IR type-level serde_rename_all.
135    #[serde(default)]
136    pub serde_rename_all: Option<String>,
137    /// Functions to exclude from PHP binding generation.
138    #[serde(default)]
139    pub exclude_functions: Vec<String>,
140    /// Types to exclude from PHP binding generation.
141    #[serde(default)]
142    pub exclude_types: Vec<String>,
143    /// Additional Cargo dependencies for this language's binding crate only.
144    #[serde(default)]
145    pub extra_dependencies: HashMap<String, toml::Value>,
146    /// Override the scaffold output directory for this language's Cargo.toml and package files.
147    #[serde(default)]
148    pub scaffold_output: Option<PathBuf>,
149    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
150    /// desired binding field name. Applied after automatic keyword escaping.
151    #[serde(default)]
152    pub rename_fields: HashMap<String, String>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct ElixirConfig {
157    pub app_name: Option<String>,
158    #[serde(default)]
159    pub features: Option<Vec<String>>,
160    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
161    /// When set, this takes priority over the IR type-level serde_rename_all.
162    #[serde(default)]
163    pub serde_rename_all: Option<String>,
164    /// Functions to exclude from Elixir NIF generation.
165    #[serde(default)]
166    pub exclude_functions: Vec<String>,
167    /// Types to exclude from Elixir NIF generation.
168    #[serde(default)]
169    pub exclude_types: Vec<String>,
170    /// Additional Cargo dependencies for this language's binding crate only.
171    #[serde(default)]
172    pub extra_dependencies: HashMap<String, toml::Value>,
173    /// Override the scaffold output directory for this language's Cargo.toml and package files.
174    #[serde(default)]
175    pub scaffold_output: Option<PathBuf>,
176    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
177    /// desired binding field name. Applied after automatic keyword escaping.
178    #[serde(default)]
179    pub rename_fields: HashMap<String, String>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct WasmConfig {
184    #[serde(default)]
185    pub exclude_functions: Vec<String>,
186    #[serde(default)]
187    pub exclude_types: Vec<String>,
188    #[serde(default)]
189    pub type_overrides: HashMap<String, String>,
190    #[serde(default)]
191    pub features: Option<Vec<String>>,
192    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
193    /// When set, this takes priority over the IR type-level serde_rename_all.
194    #[serde(default)]
195    pub serde_rename_all: Option<String>,
196    /// Prefix for generated type names (e.g. "Wasm" produces `WasmConversionOptions`).
197    /// Defaults to `"Wasm"`.
198    #[serde(default)]
199    pub type_prefix: Option<String>,
200    /// Functions to exclude from the public TypeScript re-export (index.ts) while still
201    /// generating the Rust binding. Use this when a custom module provides a wrapper.
202    #[serde(default)]
203    pub exclude_reexports: Vec<String>,
204    /// Wide-character C functions to shim for WASM external scanner interop.
205    #[serde(default)]
206    pub env_shims: Vec<String>,
207    /// Additional Cargo dependencies for the WASM binding crate only.
208    #[serde(default)]
209    pub extra_dependencies: HashMap<String, toml::Value>,
210    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
211    /// desired binding field name. Applied after automatic keyword escaping.
212    #[serde(default)]
213    pub rename_fields: HashMap<String, String>,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct FfiConfig {
218    pub prefix: Option<String>,
219    #[serde(default = "default_error_style")]
220    pub error_style: String,
221    pub header_name: Option<String>,
222    /// Native library name for Go cgo/Java Panama/C# P/Invoke (e.g., "ts_pack_ffi").
223    /// Defaults to `{prefix}_ffi`.
224    #[serde(default)]
225    pub lib_name: Option<String>,
226    /// If true, generate visitor/callback FFI support.
227    #[serde(default)]
228    pub visitor_callbacks: bool,
229    #[serde(default)]
230    pub features: Option<Vec<String>>,
231    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
232    /// When set, this takes priority over the IR type-level serde_rename_all.
233    #[serde(default)]
234    pub serde_rename_all: Option<String>,
235    /// Functions to exclude from FFI binding generation.
236    #[serde(default)]
237    pub exclude_functions: Vec<String>,
238    /// Types to exclude from FFI binding generation.
239    #[serde(default)]
240    pub exclude_types: Vec<String>,
241    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
242    /// desired binding field name. Applied after automatic keyword escaping.
243    #[serde(default)]
244    pub rename_fields: HashMap<String, String>,
245}
246
247fn default_error_style() -> String {
248    "last_error".to_string()
249}
250
251#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct GoConfig {
253    pub module: Option<String>,
254    /// Override the Go package name (default: derived from module path)
255    pub package_name: Option<String>,
256    #[serde(default)]
257    pub features: Option<Vec<String>>,
258    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
259    /// When set, this takes priority over the IR type-level serde_rename_all.
260    #[serde(default)]
261    pub serde_rename_all: Option<String>,
262    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
263    /// desired binding field name. Applied after automatic keyword escaping.
264    #[serde(default)]
265    pub rename_fields: HashMap<String, String>,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct JavaConfig {
270    pub package: Option<String>,
271    #[serde(default = "default_java_ffi_style")]
272    pub ffi_style: String,
273    #[serde(default)]
274    pub features: Option<Vec<String>>,
275    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
276    /// When set, this takes priority over the IR type-level serde_rename_all.
277    #[serde(default)]
278    pub serde_rename_all: Option<String>,
279    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
280    /// desired binding field name. Applied after automatic keyword escaping.
281    #[serde(default)]
282    pub rename_fields: HashMap<String, String>,
283}
284
285fn default_java_ffi_style() -> String {
286    "panama".to_string()
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct CSharpConfig {
291    pub namespace: Option<String>,
292    pub target_framework: Option<String>,
293    #[serde(default)]
294    pub features: Option<Vec<String>>,
295    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
296    /// When set, this takes priority over the IR type-level serde_rename_all.
297    #[serde(default)]
298    pub serde_rename_all: Option<String>,
299    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
300    /// desired binding field name. Applied after automatic keyword escaping.
301    #[serde(default)]
302    pub rename_fields: HashMap<String, String>,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct RConfig {
307    pub package_name: Option<String>,
308    #[serde(default)]
309    pub features: Option<Vec<String>>,
310    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
311    /// When set, this takes priority over the IR type-level serde_rename_all.
312    #[serde(default)]
313    pub serde_rename_all: Option<String>,
314    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
315    /// desired binding field name. Applied after automatic keyword escaping.
316    #[serde(default)]
317    pub rename_fields: HashMap<String, String>,
318}
319
320/// Custom modules that alef should declare (mod X;) but not generate.
321/// These are hand-written modules imported by the generated lib.rs.
322#[derive(Debug, Clone, Default, Serialize, Deserialize)]
323pub struct CustomModulesConfig {
324    #[serde(default)]
325    pub python: Vec<String>,
326    #[serde(default)]
327    pub node: Vec<String>,
328    #[serde(default)]
329    pub ruby: Vec<String>,
330    #[serde(default)]
331    pub php: Vec<String>,
332    #[serde(default)]
333    pub elixir: Vec<String>,
334    #[serde(default)]
335    pub wasm: Vec<String>,
336    #[serde(default)]
337    pub ffi: Vec<String>,
338    #[serde(default)]
339    pub go: Vec<String>,
340    #[serde(default)]
341    pub java: Vec<String>,
342    #[serde(default)]
343    pub csharp: Vec<String>,
344    #[serde(default)]
345    pub r: Vec<String>,
346}
347
348impl CustomModulesConfig {
349    pub fn for_language(&self, lang: Language) -> &[String] {
350        match lang {
351            Language::Python => &self.python,
352            Language::Node => &self.node,
353            Language::Ruby => &self.ruby,
354            Language::Php => &self.php,
355            Language::Elixir => &self.elixir,
356            Language::Wasm => &self.wasm,
357            Language::Ffi => &self.ffi,
358            Language::Go => &self.go,
359            Language::Java => &self.java,
360            Language::Csharp => &self.csharp,
361            Language::R => &self.r,
362            Language::Rust => &[], // Rust doesn't need custom modules (no binding crate)
363        }
364    }
365}
366
367/// Custom classes/functions from hand-written modules to register in module init.
368#[derive(Debug, Clone, Default, Serialize, Deserialize)]
369pub struct CustomRegistration {
370    #[serde(default)]
371    pub classes: Vec<String>,
372    #[serde(default)]
373    pub functions: Vec<String>,
374    #[serde(default)]
375    pub init_calls: Vec<String>,
376}
377
378/// Per-language custom registrations.
379#[derive(Debug, Clone, Default, Serialize, Deserialize)]
380pub struct CustomRegistrationsConfig {
381    #[serde(default)]
382    pub python: Option<CustomRegistration>,
383    #[serde(default)]
384    pub node: Option<CustomRegistration>,
385    #[serde(default)]
386    pub ruby: Option<CustomRegistration>,
387    #[serde(default)]
388    pub php: Option<CustomRegistration>,
389    #[serde(default)]
390    pub elixir: Option<CustomRegistration>,
391    #[serde(default)]
392    pub wasm: Option<CustomRegistration>,
393}
394
395impl CustomRegistrationsConfig {
396    pub fn for_language(&self, lang: Language) -> Option<&CustomRegistration> {
397        match lang {
398            Language::Python => self.python.as_ref(),
399            Language::Node => self.node.as_ref(),
400            Language::Ruby => self.ruby.as_ref(),
401            Language::Php => self.php.as_ref(),
402            Language::Elixir => self.elixir.as_ref(),
403            Language::Wasm => self.wasm.as_ref(),
404            _ => None,
405        }
406    }
407}