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 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
52 /// commands across all pipelines (lint, test, build, etc.).
53 /// E.g., `run_wrapper = "uv run --no-sync"` turns `ruff format packages/python` into
54 /// `uv run --no-sync ruff format packages/python`.
55 #[serde(default)]
56 pub run_wrapper: Option<String>,
57 /// Extra paths to append to default lint commands (format, check, typecheck).
58 /// Space-separated paths are appended to the command.
59 #[serde(default)]
60 pub extra_lint_paths: Vec<String>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct StubsConfig {
65 pub output: PathBuf,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct NodeConfig {
70 pub package_name: Option<String>,
71 /// Per-language feature override. When set, these features are used instead of
72 /// `[crate] features` for this language's binding crate.
73 #[serde(default)]
74 pub features: Option<Vec<String>>,
75 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
76 /// When set, this takes priority over the IR type-level serde_rename_all.
77 #[serde(default)]
78 pub serde_rename_all: Option<String>,
79 /// Prefix for generated type names (e.g. "Js" produces `JsConversionOptions`).
80 /// Defaults to `"Js"`.
81 #[serde(default)]
82 pub type_prefix: Option<String>,
83 /// Functions to exclude from Node binding generation.
84 #[serde(default)]
85 pub exclude_functions: Vec<String>,
86 /// Types to exclude from Node binding generation.
87 #[serde(default)]
88 pub exclude_types: Vec<String>,
89 /// Additional Cargo dependencies for this language's binding crate only.
90 #[serde(default)]
91 pub extra_dependencies: HashMap<String, toml::Value>,
92 /// Override the scaffold output directory for this language's Cargo.toml and package files.
93 #[serde(default)]
94 pub scaffold_output: Option<PathBuf>,
95 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
96 /// desired binding field name. Applied after automatic keyword escaping.
97 #[serde(default)]
98 pub rename_fields: HashMap<String, String>,
99 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
100 /// commands across all pipelines (lint, test, build, etc.).
101 #[serde(default)]
102 pub run_wrapper: Option<String>,
103 /// Extra paths to append to default lint commands (format, check, typecheck).
104 #[serde(default)]
105 pub extra_lint_paths: Vec<String>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct RubyConfig {
110 pub gem_name: Option<String>,
111 pub stubs: Option<StubsConfig>,
112 /// Per-language feature override. When set, these features are used instead of
113 /// `[crate] features` for this language's binding crate.
114 #[serde(default)]
115 pub features: Option<Vec<String>>,
116 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
117 /// When set, this takes priority over the IR type-level serde_rename_all.
118 #[serde(default)]
119 pub serde_rename_all: Option<String>,
120 /// Functions to exclude from Ruby binding generation.
121 #[serde(default)]
122 pub exclude_functions: Vec<String>,
123 /// Types to exclude from Ruby binding generation.
124 #[serde(default)]
125 pub exclude_types: Vec<String>,
126 /// Additional Cargo dependencies for this language's binding crate only.
127 #[serde(default)]
128 pub extra_dependencies: HashMap<String, toml::Value>,
129 /// Override the scaffold output directory for this language's Cargo.toml and package files.
130 #[serde(default)]
131 pub scaffold_output: Option<PathBuf>,
132 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
133 /// desired binding field name. Applied after automatic keyword escaping.
134 #[serde(default)]
135 pub rename_fields: HashMap<String, String>,
136 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
137 /// commands across all pipelines (lint, test, build, etc.).
138 #[serde(default)]
139 pub run_wrapper: Option<String>,
140 /// Extra paths to append to default lint commands (format, check, typecheck).
141 #[serde(default)]
142 pub extra_lint_paths: Vec<String>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct PhpConfig {
147 pub extension_name: Option<String>,
148 /// Feature gate for ext-php-rs (default: "extension-module").
149 /// All generated code is wrapped in `#[cfg(feature = "...")]`.
150 #[serde(default)]
151 pub feature_gate: Option<String>,
152 /// Output directory for generated PHP facade / stubs (e.g., `packages/php/src/`).
153 #[serde(default)]
154 pub stubs: Option<StubsConfig>,
155 #[serde(default)]
156 pub features: Option<Vec<String>>,
157 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
158 /// When set, this takes priority over the IR type-level serde_rename_all.
159 #[serde(default)]
160 pub serde_rename_all: Option<String>,
161 /// Functions to exclude from PHP binding generation.
162 #[serde(default)]
163 pub exclude_functions: Vec<String>,
164 /// Types to exclude from PHP binding generation.
165 #[serde(default)]
166 pub exclude_types: Vec<String>,
167 /// Additional Cargo dependencies for this language's binding crate only.
168 #[serde(default)]
169 pub extra_dependencies: HashMap<String, toml::Value>,
170 /// Override the scaffold output directory for this language's Cargo.toml and package files.
171 #[serde(default)]
172 pub scaffold_output: Option<PathBuf>,
173 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
174 /// desired binding field name. Applied after automatic keyword escaping.
175 #[serde(default)]
176 pub rename_fields: HashMap<String, String>,
177 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
178 /// commands across all pipelines (lint, test, build, etc.).
179 #[serde(default)]
180 pub run_wrapper: Option<String>,
181 /// Extra paths to append to default lint commands (format, check, typecheck).
182 #[serde(default)]
183 pub extra_lint_paths: Vec<String>,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct ElixirConfig {
188 pub app_name: Option<String>,
189 #[serde(default)]
190 pub features: Option<Vec<String>>,
191 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
192 /// When set, this takes priority over the IR type-level serde_rename_all.
193 #[serde(default)]
194 pub serde_rename_all: Option<String>,
195 /// Functions to exclude from Elixir NIF generation.
196 #[serde(default)]
197 pub exclude_functions: Vec<String>,
198 /// Types to exclude from Elixir NIF generation.
199 #[serde(default)]
200 pub exclude_types: Vec<String>,
201 /// Additional Cargo dependencies for this language's binding crate only.
202 #[serde(default)]
203 pub extra_dependencies: HashMap<String, toml::Value>,
204 /// Override the scaffold output directory for this language's Cargo.toml and package files.
205 #[serde(default)]
206 pub scaffold_output: Option<PathBuf>,
207 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
208 /// desired binding field name. Applied after automatic keyword escaping.
209 #[serde(default)]
210 pub rename_fields: HashMap<String, String>,
211 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
212 /// commands across all pipelines (lint, test, build, etc.).
213 #[serde(default)]
214 pub run_wrapper: Option<String>,
215 /// Extra paths to append to default lint commands (format, check, typecheck).
216 #[serde(default)]
217 pub extra_lint_paths: Vec<String>,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct WasmConfig {
222 #[serde(default)]
223 pub exclude_functions: Vec<String>,
224 #[serde(default)]
225 pub exclude_types: Vec<String>,
226 #[serde(default)]
227 pub type_overrides: HashMap<String, String>,
228 #[serde(default)]
229 pub features: Option<Vec<String>>,
230 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
231 /// When set, this takes priority over the IR type-level serde_rename_all.
232 #[serde(default)]
233 pub serde_rename_all: Option<String>,
234 /// Prefix for generated type names (e.g. "Wasm" produces `WasmConversionOptions`).
235 /// Defaults to `"Wasm"`.
236 #[serde(default)]
237 pub type_prefix: Option<String>,
238 /// Functions to exclude from the public TypeScript re-export (index.ts) while still
239 /// generating the Rust binding. Use this when a custom module provides a wrapper.
240 #[serde(default)]
241 pub exclude_reexports: Vec<String>,
242 /// Wide-character C functions to shim for WASM external scanner interop.
243 #[serde(default)]
244 pub env_shims: Vec<String>,
245 /// Additional Cargo dependencies for the WASM binding crate only.
246 #[serde(default)]
247 pub extra_dependencies: HashMap<String, toml::Value>,
248 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
249 /// desired binding field name. Applied after automatic keyword escaping.
250 #[serde(default)]
251 pub rename_fields: HashMap<String, String>,
252 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
253 /// commands across all pipelines (lint, test, build, etc.).
254 #[serde(default)]
255 pub run_wrapper: Option<String>,
256 /// Extra paths to append to default lint commands (format, check, typecheck).
257 #[serde(default)]
258 pub extra_lint_paths: Vec<String>,
259}
260
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct FfiConfig {
263 pub prefix: Option<String>,
264 #[serde(default = "default_error_style")]
265 pub error_style: String,
266 pub header_name: Option<String>,
267 /// Native library name for Go cgo/Java Panama/C# P/Invoke (e.g., "ts_pack_ffi").
268 /// Defaults to `{prefix}_ffi`.
269 #[serde(default)]
270 pub lib_name: Option<String>,
271 /// If true, generate visitor/callback FFI support.
272 #[serde(default)]
273 pub visitor_callbacks: bool,
274 #[serde(default)]
275 pub features: Option<Vec<String>>,
276 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
277 /// When set, this takes priority over the IR type-level serde_rename_all.
278 #[serde(default)]
279 pub serde_rename_all: Option<String>,
280 /// Functions to exclude from FFI binding generation.
281 #[serde(default)]
282 pub exclude_functions: Vec<String>,
283 /// Types to exclude from FFI binding generation.
284 #[serde(default)]
285 pub exclude_types: Vec<String>,
286 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
287 /// desired binding field name. Applied after automatic keyword escaping.
288 #[serde(default)]
289 pub rename_fields: HashMap<String, String>,
290}
291
292fn default_error_style() -> String {
293 "last_error".to_string()
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct GoConfig {
298 pub module: Option<String>,
299 /// Override the Go package name (default: derived from module path)
300 pub package_name: Option<String>,
301 #[serde(default)]
302 pub features: Option<Vec<String>>,
303 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
304 /// When set, this takes priority over the IR type-level serde_rename_all.
305 #[serde(default)]
306 pub serde_rename_all: Option<String>,
307 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
308 /// desired binding field name. Applied after automatic keyword escaping.
309 #[serde(default)]
310 pub rename_fields: HashMap<String, String>,
311 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
312 /// commands across all pipelines (lint, test, build, etc.).
313 #[serde(default)]
314 pub run_wrapper: Option<String>,
315 /// Extra paths to append to default lint commands (format, check, typecheck).
316 #[serde(default)]
317 pub extra_lint_paths: Vec<String>,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct JavaConfig {
322 pub package: Option<String>,
323 #[serde(default = "default_java_ffi_style")]
324 pub ffi_style: String,
325 #[serde(default)]
326 pub features: Option<Vec<String>>,
327 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
328 /// When set, this takes priority over the IR type-level serde_rename_all.
329 #[serde(default)]
330 pub serde_rename_all: Option<String>,
331 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
332 /// desired binding field name. Applied after automatic keyword escaping.
333 #[serde(default)]
334 pub rename_fields: HashMap<String, String>,
335 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
336 /// commands across all pipelines (lint, test, build, etc.).
337 #[serde(default)]
338 pub run_wrapper: Option<String>,
339 /// Extra paths to append to default lint commands (format, check, typecheck).
340 /// Ignored when project_file is set.
341 #[serde(default)]
342 pub extra_lint_paths: Vec<String>,
343 /// Project file for Maven/Gradle (e.g., "pom.xml", "build.gradle"). When set, default
344 /// lint/build/test commands target this file instead of the output directory.
345 #[serde(default)]
346 pub project_file: Option<String>,
347}
348
349fn default_java_ffi_style() -> String {
350 "panama".to_string()
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct CSharpConfig {
355 pub namespace: Option<String>,
356 pub target_framework: Option<String>,
357 #[serde(default)]
358 pub features: Option<Vec<String>>,
359 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
360 /// When set, this takes priority over the IR type-level serde_rename_all.
361 #[serde(default)]
362 pub serde_rename_all: Option<String>,
363 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
364 /// desired binding field name. Applied after automatic keyword escaping.
365 #[serde(default)]
366 pub rename_fields: HashMap<String, String>,
367 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
368 /// commands across all pipelines (lint, test, build, etc.).
369 #[serde(default)]
370 pub run_wrapper: Option<String>,
371 /// Extra paths to append to default lint commands (format, check, typecheck).
372 /// Ignored when project_file is set.
373 #[serde(default)]
374 pub extra_lint_paths: Vec<String>,
375 /// Project file for C# (e.g., "MyProject.csproj", "MySolution.sln"). When set, default
376 /// lint/build/test commands target this file instead of the output directory.
377 #[serde(default)]
378 pub project_file: Option<String>,
379}
380
381#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct RConfig {
383 pub package_name: Option<String>,
384 #[serde(default)]
385 pub features: Option<Vec<String>>,
386 /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
387 /// When set, this takes priority over the IR type-level serde_rename_all.
388 #[serde(default)]
389 pub serde_rename_all: Option<String>,
390 /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
391 /// desired binding field name. Applied after automatic keyword escaping.
392 #[serde(default)]
393 pub rename_fields: HashMap<String, String>,
394 /// Prefix wrapper for default tool invocations. When set, prepends this string to default
395 /// commands across all pipelines (lint, test, build, etc.).
396 #[serde(default)]
397 pub run_wrapper: Option<String>,
398 /// Extra paths to append to default lint commands (format, check, typecheck).
399 #[serde(default)]
400 pub extra_lint_paths: Vec<String>,
401}
402
403/// Custom modules that alef should declare (mod X;) but not generate.
404/// These are hand-written modules imported by the generated lib.rs.
405#[derive(Debug, Clone, Default, Serialize, Deserialize)]
406pub struct CustomModulesConfig {
407 #[serde(default)]
408 pub python: Vec<String>,
409 #[serde(default)]
410 pub node: Vec<String>,
411 #[serde(default)]
412 pub ruby: Vec<String>,
413 #[serde(default)]
414 pub php: Vec<String>,
415 #[serde(default)]
416 pub elixir: Vec<String>,
417 #[serde(default)]
418 pub wasm: Vec<String>,
419 #[serde(default)]
420 pub ffi: Vec<String>,
421 #[serde(default)]
422 pub go: Vec<String>,
423 #[serde(default)]
424 pub java: Vec<String>,
425 #[serde(default)]
426 pub csharp: Vec<String>,
427 #[serde(default)]
428 pub r: Vec<String>,
429}
430
431impl CustomModulesConfig {
432 pub fn for_language(&self, lang: Language) -> &[String] {
433 match lang {
434 Language::Python => &self.python,
435 Language::Node => &self.node,
436 Language::Ruby => &self.ruby,
437 Language::Php => &self.php,
438 Language::Elixir => &self.elixir,
439 Language::Wasm => &self.wasm,
440 Language::Ffi => &self.ffi,
441 Language::Go => &self.go,
442 Language::Java => &self.java,
443 Language::Csharp => &self.csharp,
444 Language::R => &self.r,
445 Language::Rust => &[], // Rust doesn't need custom modules (no binding crate)
446 }
447 }
448}
449
450/// Custom classes/functions from hand-written modules to register in module init.
451#[derive(Debug, Clone, Default, Serialize, Deserialize)]
452pub struct CustomRegistration {
453 #[serde(default)]
454 pub classes: Vec<String>,
455 #[serde(default)]
456 pub functions: Vec<String>,
457 #[serde(default)]
458 pub init_calls: Vec<String>,
459}
460
461/// Per-language custom registrations.
462#[derive(Debug, Clone, Default, Serialize, Deserialize)]
463pub struct CustomRegistrationsConfig {
464 #[serde(default)]
465 pub python: Option<CustomRegistration>,
466 #[serde(default)]
467 pub node: Option<CustomRegistration>,
468 #[serde(default)]
469 pub ruby: Option<CustomRegistration>,
470 #[serde(default)]
471 pub php: Option<CustomRegistration>,
472 #[serde(default)]
473 pub elixir: Option<CustomRegistration>,
474 #[serde(default)]
475 pub wasm: Option<CustomRegistration>,
476}
477
478impl CustomRegistrationsConfig {
479 pub fn for_language(&self, lang: Language) -> Option<&CustomRegistration> {
480 match lang {
481 Language::Python => self.python.as_ref(),
482 Language::Node => self.node.as_ref(),
483 Language::Ruby => self.ruby.as_ref(),
484 Language::Php => self.php.as_ref(),
485 Language::Elixir => self.elixir.as_ref(),
486 Language::Wasm => self.wasm.as_ref(),
487 _ => None,
488 }
489 }
490}