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}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct StubsConfig {
50    pub output: PathBuf,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct NodeConfig {
55    pub package_name: Option<String>,
56    /// Per-language feature override. When set, these features are used instead of
57    /// `[crate] features` for this language's binding crate.
58    #[serde(default)]
59    pub features: Option<Vec<String>>,
60    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
61    /// When set, this takes priority over the IR type-level serde_rename_all.
62    #[serde(default)]
63    pub serde_rename_all: Option<String>,
64    /// Prefix for generated type names (e.g. "Js" produces `JsConversionOptions`).
65    /// Defaults to `"Js"`.
66    #[serde(default)]
67    pub type_prefix: Option<String>,
68    /// Functions to exclude from Node binding generation.
69    #[serde(default)]
70    pub exclude_functions: Vec<String>,
71    /// Types to exclude from Node binding generation.
72    #[serde(default)]
73    pub exclude_types: Vec<String>,
74    /// Additional Cargo dependencies for this language's binding crate only.
75    #[serde(default)]
76    pub extra_dependencies: HashMap<String, toml::Value>,
77    /// Override the scaffold output directory for this language's Cargo.toml and package files.
78    #[serde(default)]
79    pub scaffold_output: Option<PathBuf>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct RubyConfig {
84    pub gem_name: Option<String>,
85    pub stubs: Option<StubsConfig>,
86    /// Per-language feature override. When set, these features are used instead of
87    /// `[crate] features` for this language's binding crate.
88    #[serde(default)]
89    pub features: Option<Vec<String>>,
90    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
91    /// When set, this takes priority over the IR type-level serde_rename_all.
92    #[serde(default)]
93    pub serde_rename_all: Option<String>,
94    /// Additional Cargo dependencies for this language's binding crate only.
95    #[serde(default)]
96    pub extra_dependencies: HashMap<String, toml::Value>,
97    /// Override the scaffold output directory for this language's Cargo.toml and package files.
98    #[serde(default)]
99    pub scaffold_output: Option<PathBuf>,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct PhpConfig {
104    pub extension_name: Option<String>,
105    /// Feature gate for ext-php-rs (default: "extension-module").
106    /// All generated code is wrapped in `#[cfg(feature = "...")]`.
107    #[serde(default)]
108    pub feature_gate: Option<String>,
109    /// Output directory for generated PHP facade / stubs (e.g., `packages/php/src/`).
110    #[serde(default)]
111    pub stubs: Option<StubsConfig>,
112    #[serde(default)]
113    pub features: Option<Vec<String>>,
114    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
115    /// When set, this takes priority over the IR type-level serde_rename_all.
116    #[serde(default)]
117    pub serde_rename_all: Option<String>,
118    /// Functions to exclude from PHP binding generation.
119    #[serde(default)]
120    pub exclude_functions: Vec<String>,
121    /// Types to exclude from PHP binding generation.
122    #[serde(default)]
123    pub exclude_types: Vec<String>,
124    /// Additional Cargo dependencies for this language's binding crate only.
125    #[serde(default)]
126    pub extra_dependencies: HashMap<String, toml::Value>,
127    /// Override the scaffold output directory for this language's Cargo.toml and package files.
128    #[serde(default)]
129    pub scaffold_output: Option<PathBuf>,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct ElixirConfig {
134    pub app_name: Option<String>,
135    #[serde(default)]
136    pub features: Option<Vec<String>>,
137    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
138    /// When set, this takes priority over the IR type-level serde_rename_all.
139    #[serde(default)]
140    pub serde_rename_all: Option<String>,
141    /// Functions to exclude from Elixir NIF generation.
142    #[serde(default)]
143    pub exclude_functions: Vec<String>,
144    /// Types to exclude from Elixir NIF generation.
145    #[serde(default)]
146    pub exclude_types: Vec<String>,
147    /// Additional Cargo dependencies for this language's binding crate only.
148    #[serde(default)]
149    pub extra_dependencies: HashMap<String, toml::Value>,
150    /// Override the scaffold output directory for this language's Cargo.toml and package files.
151    #[serde(default)]
152    pub scaffold_output: Option<PathBuf>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct WasmConfig {
157    #[serde(default)]
158    pub exclude_functions: Vec<String>,
159    #[serde(default)]
160    pub exclude_types: Vec<String>,
161    #[serde(default)]
162    pub type_overrides: HashMap<String, String>,
163    #[serde(default)]
164    pub features: Option<Vec<String>>,
165    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
166    /// When set, this takes priority over the IR type-level serde_rename_all.
167    #[serde(default)]
168    pub serde_rename_all: Option<String>,
169    /// Prefix for generated type names (e.g. "Wasm" produces `WasmConversionOptions`).
170    /// Defaults to `"Wasm"`.
171    #[serde(default)]
172    pub type_prefix: Option<String>,
173    /// Functions to exclude from the public TypeScript re-export (index.ts) while still
174    /// generating the Rust binding. Use this when a custom module provides a wrapper.
175    #[serde(default)]
176    pub exclude_reexports: Vec<String>,
177    /// Wide-character C functions to shim for WASM external scanner interop.
178    #[serde(default)]
179    pub env_shims: Vec<String>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct FfiConfig {
184    pub prefix: Option<String>,
185    #[serde(default = "default_error_style")]
186    pub error_style: String,
187    pub header_name: Option<String>,
188    /// Native library name for Go cgo/Java Panama/C# P/Invoke (e.g., "ts_pack_ffi").
189    /// Defaults to `{prefix}_ffi`.
190    #[serde(default)]
191    pub lib_name: Option<String>,
192    /// If true, generate visitor/callback FFI support.
193    #[serde(default)]
194    pub visitor_callbacks: bool,
195    #[serde(default)]
196    pub features: Option<Vec<String>>,
197    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
198    /// When set, this takes priority over the IR type-level serde_rename_all.
199    #[serde(default)]
200    pub serde_rename_all: Option<String>,
201    /// Functions to exclude from FFI binding generation.
202    #[serde(default)]
203    pub exclude_functions: Vec<String>,
204    /// Types to exclude from FFI binding generation.
205    #[serde(default)]
206    pub exclude_types: Vec<String>,
207}
208
209fn default_error_style() -> String {
210    "last_error".to_string()
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct GoConfig {
215    pub module: Option<String>,
216    /// Override the Go package name (default: derived from module path)
217    pub package_name: Option<String>,
218    #[serde(default)]
219    pub features: Option<Vec<String>>,
220    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
221    /// When set, this takes priority over the IR type-level serde_rename_all.
222    #[serde(default)]
223    pub serde_rename_all: Option<String>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct JavaConfig {
228    pub package: Option<String>,
229    #[serde(default = "default_java_ffi_style")]
230    pub ffi_style: String,
231    #[serde(default)]
232    pub features: Option<Vec<String>>,
233    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
234    /// When set, this takes priority over the IR type-level serde_rename_all.
235    #[serde(default)]
236    pub serde_rename_all: Option<String>,
237}
238
239fn default_java_ffi_style() -> String {
240    "panama".to_string()
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct CSharpConfig {
245    pub namespace: Option<String>,
246    pub target_framework: Option<String>,
247    #[serde(default)]
248    pub features: Option<Vec<String>>,
249    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
250    /// When set, this takes priority over the IR type-level serde_rename_all.
251    #[serde(default)]
252    pub serde_rename_all: Option<String>,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct RConfig {
257    pub package_name: Option<String>,
258    #[serde(default)]
259    pub features: Option<Vec<String>>,
260    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
261    /// When set, this takes priority over the IR type-level serde_rename_all.
262    #[serde(default)]
263    pub serde_rename_all: Option<String>,
264}
265
266/// Custom modules that alef should declare (mod X;) but not generate.
267/// These are hand-written modules imported by the generated lib.rs.
268#[derive(Debug, Clone, Default, Serialize, Deserialize)]
269pub struct CustomModulesConfig {
270    #[serde(default)]
271    pub python: Vec<String>,
272    #[serde(default)]
273    pub node: Vec<String>,
274    #[serde(default)]
275    pub ruby: Vec<String>,
276    #[serde(default)]
277    pub php: Vec<String>,
278    #[serde(default)]
279    pub elixir: Vec<String>,
280    #[serde(default)]
281    pub wasm: Vec<String>,
282    #[serde(default)]
283    pub ffi: Vec<String>,
284    #[serde(default)]
285    pub go: Vec<String>,
286    #[serde(default)]
287    pub java: Vec<String>,
288    #[serde(default)]
289    pub csharp: Vec<String>,
290    #[serde(default)]
291    pub r: Vec<String>,
292}
293
294impl CustomModulesConfig {
295    pub fn for_language(&self, lang: Language) -> &[String] {
296        match lang {
297            Language::Python => &self.python,
298            Language::Node => &self.node,
299            Language::Ruby => &self.ruby,
300            Language::Php => &self.php,
301            Language::Elixir => &self.elixir,
302            Language::Wasm => &self.wasm,
303            Language::Ffi => &self.ffi,
304            Language::Go => &self.go,
305            Language::Java => &self.java,
306            Language::Csharp => &self.csharp,
307            Language::R => &self.r,
308            Language::Rust => &[], // Rust doesn't need custom modules (no binding crate)
309        }
310    }
311}
312
313/// Custom classes/functions from hand-written modules to register in module init.
314#[derive(Debug, Clone, Default, Serialize, Deserialize)]
315pub struct CustomRegistration {
316    #[serde(default)]
317    pub classes: Vec<String>,
318    #[serde(default)]
319    pub functions: Vec<String>,
320    #[serde(default)]
321    pub init_calls: Vec<String>,
322}
323
324/// Per-language custom registrations.
325#[derive(Debug, Clone, Default, Serialize, Deserialize)]
326pub struct CustomRegistrationsConfig {
327    #[serde(default)]
328    pub python: Option<CustomRegistration>,
329    #[serde(default)]
330    pub node: Option<CustomRegistration>,
331    #[serde(default)]
332    pub ruby: Option<CustomRegistration>,
333    #[serde(default)]
334    pub php: Option<CustomRegistration>,
335    #[serde(default)]
336    pub elixir: Option<CustomRegistration>,
337    #[serde(default)]
338    pub wasm: Option<CustomRegistration>,
339}
340
341impl CustomRegistrationsConfig {
342    pub fn for_language(&self, lang: Language) -> Option<&CustomRegistration> {
343        match lang {
344            Language::Python => self.python.as_ref(),
345            Language::Node => self.node.as_ref(),
346            Language::Ruby => self.ruby.as_ref(),
347            Language::Php => self.php.as_ref(),
348            Language::Elixir => self.elixir.as_ref(),
349            Language::Wasm => self.wasm.as_ref(),
350            _ => None,
351        }
352    }
353}