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}