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/// Configuration for a single capsule type entry in `PythonConfig::capsule_types`.
8///
9/// Supports two TOML forms via `#[serde(untagged)]`:
10///
11/// - String: `Language = "tree_sitter.Language"` → capsule round-trip via `into_raw()`
12/// - Struct: `Parser = { python_type = "tree_sitter.Parser", construct_from = "Language" }` → Python-side construction
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
14#[serde(untagged)]
15pub enum CapsuleTypeConfig {
16    /// Capsule round-trip: the Rust type exposes `into_raw()` returning a raw pointer.
17    /// The generated code calls `PyCapsule_New(value.into_raw(), capsule_name, None)` on return,
18    /// and `PyCapsule_GetPointer` + `from_raw()` on input.
19    ///
20    /// Value is the fully-qualified Python capsule name (e.g. `"tree_sitter.Language"`).
21    Capsule(String),
22    /// Python-side construction: the type does not have a direct `into_raw()`.
23    /// Instead, the generated code constructs the Python type by calling a Python factory
24    /// (e.g. `tree_sitter.Parser(language)`) where `language` is a bound capsule argument.
25    ConstructFrom {
26        /// The fully-qualified Python type to import and call (e.g. `"tree_sitter.Parser"`).
27        python_type: String,
28        /// The capsule-type argument name to pass to the Python constructor.
29        /// Must be one of the other capsule-type entries (e.g. `"Language"`).
30        construct_from: String,
31    },
32}
33
34impl CapsuleTypeConfig {
35    /// Returns the Python type string (dotted path) for this config entry.
36    pub fn python_type(&self) -> &str {
37        match self {
38            Self::Capsule(name) => name,
39            Self::ConstructFrom { python_type, .. } => python_type,
40        }
41    }
42
43    /// Returns the `construct_from` dependency type name, if this is a `ConstructFrom` entry.
44    pub fn construct_from(&self) -> Option<&str> {
45        match self {
46            Self::ConstructFrom { construct_from, .. } => Some(construct_from.as_str()),
47            Self::Capsule(_) => None,
48        }
49    }
50
51    /// Returns true when this entry represents a raw capsule round-trip (not Python-side construction).
52    pub fn is_capsule_roundtrip(&self) -> bool {
53        matches!(self, Self::Capsule(_))
54    }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct PythonConfig {
59    pub module_name: Option<String>,
60    pub async_runtime: Option<String>,
61    pub stubs: Option<StubsConfig>,
62    /// PyPI package name (e.g. `"html-to-markdown"`). Used as the `[project] name` in
63    /// `pyproject.toml` and to derive the `python-packages` list for maturin.
64    /// Defaults to the crate name.
65    #[serde(default)]
66    pub pip_name: Option<String>,
67    /// Per-language feature override. When set, these features are used instead of
68    /// `[crate] features` for this language's binding crate.
69    #[serde(default)]
70    pub features: Option<Vec<String>>,
71    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
72    /// When set, this takes priority over the IR type-level serde_rename_all.
73    #[serde(default)]
74    pub serde_rename_all: Option<String>,
75    /// Map of type name -> capsule config for PyCapsule pass-through.
76    /// Types listed here are emitted as PyCapsule_New / PyCapsule_GetPointer instead of
77    /// opaque `#[pyclass]` wrappers. Use `CapsuleTypeConfig::Capsule` for raw capsule
78    /// round-trips and `CapsuleTypeConfig::ConstructFrom` for Python-side construction.
79    #[serde(default)]
80    pub capsule_types: HashMap<String, CapsuleTypeConfig>,
81    /// When true, wrap blocking function bodies in py.allow_threads() to release the GIL.
82    // TODO: Wire into gen_bindings.rs to emit py.allow_threads(|| { ... }) for non-async functions.
83    #[serde(default)]
84    pub release_gil: bool,
85    /// Functions to exclude from Python binding generation.
86    #[serde(default)]
87    pub exclude_functions: Vec<String>,
88    /// Types to exclude from Python binding generation.
89    #[serde(default)]
90    pub exclude_types: Vec<String>,
91    /// Additional Cargo dependencies for this language's binding crate only.
92    #[serde(default)]
93    pub extra_dependencies: HashMap<String, toml::Value>,
94    /// Override the scaffold output directory for this language's Cargo.toml and package files.
95    #[serde(default)]
96    pub scaffold_output: Option<PathBuf>,
97    /// Per-field name remapping for this language. Key is `TypeName.field_name` (e.g.
98    /// `"LayoutDetection.class"`), value is the desired binding field name. Applied after
99    /// automatic keyword escaping, so an explicit entry takes priority.
100    #[serde(default)]
101    pub rename_fields: HashMap<String, String>,
102    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
103    /// commands across all pipelines (lint, test, build, etc.).
104    /// E.g., `run_wrapper = "uv run --no-sync"` turns `ruff format packages/python` into
105    /// `uv run --no-sync ruff format packages/python`.
106    #[serde(default)]
107    pub run_wrapper: Option<String>,
108    /// Extra paths to append to default lint commands (format, check, typecheck).
109    /// Space-separated paths are appended to the command.
110    #[serde(default)]
111    pub extra_lint_paths: Vec<String>,
112    /// Additional `from <module> import <symbol>` lines to emit in the generated `__init__.py`.
113    /// Key is the relative or absolute Python module path (e.g. `"._supported_languages"`),
114    /// value is the list of symbols to import. The symbols are also added to `__all__`.
115    ///
116    /// Use this to re-export hand-written sibling modules (e.g. generated by a project's own
117    /// build script) without alef's cleanup culling them. The hand-written file must NOT contain
118    /// the substrings `"DO NOT EDIT"`, `"auto-generated by alef"`, or `"AUTO-GENERATED by alef"`
119    /// in its first 5 lines, or alef's cleanup pipeline will treat it as a stale alef artifact.
120    #[serde(default)]
121    pub extra_init_imports: std::collections::BTreeMap<String, Vec<String>>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct StubsConfig {
126    pub output: PathBuf,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct NodeConfig {
131    pub package_name: Option<String>,
132    /// Per-language feature override. When set, these features are used instead of
133    /// `[crate] features` for this language's binding crate.
134    #[serde(default)]
135    pub features: Option<Vec<String>>,
136    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
137    /// When set, this takes priority over the IR type-level serde_rename_all.
138    #[serde(default)]
139    pub serde_rename_all: Option<String>,
140    /// Prefix for generated type names (e.g. "Js" produces `JsConversionOptions`).
141    /// Defaults to `"Js"`.
142    #[serde(default)]
143    pub type_prefix: Option<String>,
144    /// Functions to exclude from Node binding generation.
145    #[serde(default)]
146    pub exclude_functions: Vec<String>,
147    /// Types to exclude from Node binding generation.
148    #[serde(default)]
149    pub exclude_types: Vec<String>,
150    /// Additional Cargo dependencies for this language's binding crate only.
151    #[serde(default)]
152    pub extra_dependencies: HashMap<String, toml::Value>,
153    /// Override the scaffold output directory for this language's Cargo.toml and package files.
154    #[serde(default)]
155    pub scaffold_output: Option<PathBuf>,
156    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
157    /// desired binding field name. Applied after automatic keyword escaping.
158    #[serde(default)]
159    pub rename_fields: HashMap<String, String>,
160    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
161    /// commands across all pipelines (lint, test, build, etc.).
162    #[serde(default)]
163    pub run_wrapper: Option<String>,
164    /// Extra paths to append to default lint commands (format, check, typecheck).
165    #[serde(default)]
166    pub extra_lint_paths: Vec<String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct RubyConfig {
171    pub gem_name: Option<String>,
172    pub stubs: Option<StubsConfig>,
173    /// Per-language feature override. When set, these features are used instead of
174    /// `[crate] features` for this language's binding crate.
175    #[serde(default)]
176    pub features: Option<Vec<String>>,
177    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
178    /// When set, this takes priority over the IR type-level serde_rename_all.
179    #[serde(default)]
180    pub serde_rename_all: Option<String>,
181    /// Functions to exclude from Ruby binding generation.
182    #[serde(default)]
183    pub exclude_functions: Vec<String>,
184    /// Types to exclude from Ruby binding generation.
185    #[serde(default)]
186    pub exclude_types: Vec<String>,
187    /// Additional Cargo dependencies for this language's binding crate only.
188    #[serde(default)]
189    pub extra_dependencies: HashMap<String, toml::Value>,
190    /// Override the scaffold output directory for this language's Cargo.toml and package files.
191    #[serde(default)]
192    pub scaffold_output: Option<PathBuf>,
193    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
194    /// desired binding field name. Applied after automatic keyword escaping.
195    #[serde(default)]
196    pub rename_fields: HashMap<String, String>,
197    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
198    /// commands across all pipelines (lint, test, build, etc.).
199    #[serde(default)]
200    pub run_wrapper: Option<String>,
201    /// Extra paths to append to default lint commands (format, check, typecheck).
202    #[serde(default)]
203    pub extra_lint_paths: Vec<String>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct PhpConfig {
208    pub extension_name: Option<String>,
209    /// Cargo crate name for the PHP binding (e.g. `"ts-pack-core-php"`).
210    /// Used to derive the shared library filename in the e2e test runner.
211    /// When absent, the lib name is derived from `extension_name` by appending `_php`.
212    #[serde(default)]
213    pub cargo_crate_name: Option<String>,
214    /// Override the PHP namespace used for class registration and PSR-4 autoloading.
215    ///
216    /// When set, this value is used verbatim as the PHP namespace (e.g. `"HtmlToMarkdown"`).
217    /// When absent, the namespace is derived from `extension_name` by splitting on `_` and
218    /// converting each segment to PascalCase (e.g. `html_to_markdown` → `Html\To\Markdown`).
219    #[serde(default)]
220    pub namespace: Option<String>,
221    /// Feature gate for ext-php-rs (default: "extension-module").
222    /// All generated code is wrapped in `#[cfg(feature = "...")]`.
223    #[serde(default)]
224    pub feature_gate: Option<String>,
225    /// Output directory for generated PHP facade / stubs (e.g., `packages/php/src/`).
226    #[serde(default)]
227    pub stubs: Option<StubsConfig>,
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    /// Functions to exclude from PHP binding generation.
235    #[serde(default)]
236    pub exclude_functions: Vec<String>,
237    /// Types to exclude from PHP binding generation.
238    #[serde(default)]
239    pub exclude_types: Vec<String>,
240    /// Additional Cargo dependencies for this language's binding crate only.
241    #[serde(default)]
242    pub extra_dependencies: HashMap<String, toml::Value>,
243    /// Override the scaffold output directory for this language's Cargo.toml and package files.
244    #[serde(default)]
245    pub scaffold_output: Option<PathBuf>,
246    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
247    /// desired binding field name. Applied after automatic keyword escaping.
248    #[serde(default)]
249    pub rename_fields: HashMap<String, String>,
250    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
251    /// commands across all pipelines (lint, test, build, etc.).
252    #[serde(default)]
253    pub run_wrapper: Option<String>,
254    /// Extra paths to append to default lint commands (format, check, typecheck).
255    #[serde(default)]
256    pub extra_lint_paths: Vec<String>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct ElixirConfig {
261    pub app_name: Option<String>,
262    #[serde(default)]
263    pub features: Option<Vec<String>>,
264    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
265    /// When set, this takes priority over the IR type-level serde_rename_all.
266    #[serde(default)]
267    pub serde_rename_all: Option<String>,
268    /// Functions to exclude from Elixir NIF generation.
269    #[serde(default)]
270    pub exclude_functions: Vec<String>,
271    /// Types to exclude from Elixir NIF generation.
272    #[serde(default)]
273    pub exclude_types: Vec<String>,
274    /// Additional Cargo dependencies for this language's binding crate only.
275    #[serde(default)]
276    pub extra_dependencies: HashMap<String, toml::Value>,
277    /// Override the scaffold output directory for this language's Cargo.toml and package files.
278    #[serde(default)]
279    pub scaffold_output: Option<PathBuf>,
280    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
281    /// desired binding field name. Applied after automatic keyword escaping.
282    #[serde(default)]
283    pub rename_fields: HashMap<String, String>,
284    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
285    /// commands across all pipelines (lint, test, build, etc.).
286    #[serde(default)]
287    pub run_wrapper: Option<String>,
288    /// Extra paths to append to default lint commands (format, check, typecheck).
289    #[serde(default)]
290    pub extra_lint_paths: Vec<String>,
291    /// Functions that should be scheduled on the dirty CPU scheduler.
292    /// HTML parsing and other CPU-intensive NIFs should be listed here to avoid
293    /// blocking BEAM scheduler threads.
294    #[serde(default)]
295    pub cpu_bound_functions: Vec<String>,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct WasmConfig {
300    #[serde(default)]
301    pub exclude_functions: Vec<String>,
302    #[serde(default)]
303    pub exclude_types: Vec<String>,
304    #[serde(default)]
305    pub type_overrides: HashMap<String, String>,
306    #[serde(default)]
307    pub features: Option<Vec<String>>,
308    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
309    /// When set, this takes priority over the IR type-level serde_rename_all.
310    #[serde(default)]
311    pub serde_rename_all: Option<String>,
312    /// Prefix for generated type names (e.g. "Wasm" produces `WasmConversionOptions`).
313    /// Defaults to `"Wasm"`.
314    #[serde(default)]
315    pub type_prefix: Option<String>,
316    /// Functions to exclude from the public TypeScript re-export (index.ts) while still
317    /// generating the Rust binding. Use this when a custom module provides a wrapper.
318    #[serde(default)]
319    pub exclude_reexports: Vec<String>,
320    /// Wide-character C functions to shim for WASM external scanner interop.
321    #[serde(default)]
322    pub env_shims: Vec<String>,
323    /// Additional Cargo dependencies for the WASM binding crate only.
324    #[serde(default)]
325    pub extra_dependencies: HashMap<String, toml::Value>,
326    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
327    /// desired binding field name. Applied after automatic keyword escaping.
328    #[serde(default)]
329    pub rename_fields: HashMap<String, String>,
330    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
331    /// commands across all pipelines (lint, test, build, etc.).
332    #[serde(default)]
333    pub run_wrapper: Option<String>,
334    /// Extra paths to append to default lint commands (format, check, typecheck).
335    #[serde(default)]
336    pub extra_lint_paths: Vec<String>,
337    /// Override the core Cargo dependency name and path for the WASM binding crate.
338    /// When set, the binding `Cargo.toml` depends on this crate (resolved as
339    /// `../<override>`) instead of the umbrella `[crate.name]`. Use this to point
340    /// the WASM binding at a wasm-safe sub-crate while other languages keep the
341    /// facade. Defaults to unset.
342    #[serde(default)]
343    pub core_crate_override: Option<String>,
344    /// Keys to subtract from the merged `extra_dependencies` set for this
345    /// language only. Useful when `[crate.extra_dependencies]` lists sibling
346    /// crates that the WASM target cannot link.
347    #[serde(default)]
348    pub exclude_extra_dependencies: Vec<String>,
349    /// Hand-written Rust modules to declare in the generated lib.rs with `pub mod <name>;`
350    /// and re-export with `pub use <name>::*;`. Separate from `[custom_modules].wasm` which
351    /// only adds TypeScript `export *` re-exports. Use this for Rust-side dispatch/glue modules.
352    #[serde(default)]
353    pub custom_rust_modules: Vec<String>,
354    /// Per-type field exclusions for the generated From impls and binding struct.
355    /// Key is the type name (e.g. "ServerConfig"), value is a list of field names to skip.
356    /// Use when source fields are gated behind `#[cfg(not(target_arch = "wasm32"))]` and
357    /// therefore don't exist in the wasm32 compilation environment.
358    #[serde(default)]
359    pub exclude_fields: HashMap<String, Vec<String>>,
360    /// Source crate names whose types are re-exported by the `core_crate_override`
361    /// crate. References to `<original_crate>::TypeName` in generated code are
362    /// rewritten to `<override_crate>::TypeName`. Only meaningful when
363    /// `core_crate_override` is set.
364    /// Example: with `core_crate_override = "mylib-http"`, setting
365    /// `source_crate_remaps = ["mylib-core", "mylib"]` rewrites
366    /// `mylib_core::Method` and `mylib::Method` references to
367    /// `mylib_http::Method` (assumes `mylib-http` re-exports them via
368    /// `pub use mylib_core::*`).
369    #[serde(default)]
370    pub source_crate_remaps: Vec<String>,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct FfiConfig {
375    pub prefix: Option<String>,
376    #[serde(default = "default_error_style")]
377    pub error_style: String,
378    pub header_name: Option<String>,
379    /// Native library name for Go cgo/Java Panama/C# P/Invoke (e.g., "ts_pack_ffi").
380    /// Defaults to `{prefix}_ffi`.
381    #[serde(default)]
382    pub lib_name: Option<String>,
383    /// If true, generate visitor/callback FFI support.
384    #[serde(default)]
385    pub visitor_callbacks: bool,
386    #[serde(default)]
387    pub features: Option<Vec<String>>,
388    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
389    /// When set, this takes priority over the IR type-level serde_rename_all.
390    #[serde(default)]
391    pub serde_rename_all: Option<String>,
392    /// Functions to exclude from FFI binding generation.
393    #[serde(default)]
394    pub exclude_functions: Vec<String>,
395    /// Types to exclude from FFI binding generation.
396    #[serde(default)]
397    pub exclude_types: Vec<String>,
398    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
399    /// desired binding field name. Applied after automatic keyword escaping.
400    #[serde(default)]
401    pub rename_fields: HashMap<String, String>,
402    /// Rust expression used to construct an error value of this crate's
403    /// `error_type` from a runtime `String` message inside generated FFI
404    /// trait-bridge plugin shims (`plugin_impl_initialize`, `plugin_impl_shutdown`).
405    ///
406    /// The expression has access to a local variable `msg: String` containing
407    /// the underlying error message and is interpolated verbatim. Example
408    /// values:
409    ///
410    /// ```toml
411    /// # downstream whose error type has a struct variant with two fields:
412    /// plugin_error_constructor = """
413    /// kreuzberg::KreuzbergError::Plugin { message: msg, plugin_name: String::new() }
414    /// """
415    ///
416    /// # downstream whose error type implements `From<String>`:
417    /// plugin_error_constructor = "MyError::from(msg)"
418    /// ```
419    ///
420    /// Defaults to `None`. When unset, the plugin shim still emits — backends
421    /// fall back to a `format!("{}: {}", prefix, msg)`-style construction via
422    /// the configured `error_constructor`. Downstreams that don't expose
423    /// trait-bridged plugins can ignore this knob entirely.
424    #[serde(default)]
425    pub plugin_error_constructor: Option<String>,
426}
427
428fn default_error_style() -> String {
429    "last_error".to_string()
430}
431
432#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct GoConfig {
434    pub module: Option<String>,
435    /// Override the Go package name (default: derived from module path)
436    pub package_name: Option<String>,
437    #[serde(default)]
438    pub features: Option<Vec<String>>,
439    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
440    /// When set, this takes priority over the IR type-level serde_rename_all.
441    #[serde(default)]
442    pub serde_rename_all: Option<String>,
443    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
444    /// desired binding field name. Applied after automatic keyword escaping.
445    #[serde(default)]
446    pub rename_fields: HashMap<String, String>,
447    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
448    /// commands across all pipelines (lint, test, build, etc.).
449    #[serde(default)]
450    pub run_wrapper: Option<String>,
451    /// Extra paths to append to default lint commands (format, check, typecheck).
452    #[serde(default)]
453    pub extra_lint_paths: Vec<String>,
454}
455
456#[derive(Debug, Clone, Serialize, Deserialize)]
457pub struct JavaConfig {
458    pub package: Option<String>,
459    #[serde(default = "default_java_ffi_style")]
460    pub ffi_style: String,
461    #[serde(default)]
462    pub features: Option<Vec<String>>,
463    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
464    /// When set, this takes priority over the IR type-level serde_rename_all.
465    #[serde(default)]
466    pub serde_rename_all: Option<String>,
467    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
468    /// desired binding field name. Applied after automatic keyword escaping.
469    #[serde(default)]
470    pub rename_fields: HashMap<String, String>,
471    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
472    /// commands across all pipelines (lint, test, build, etc.).
473    #[serde(default)]
474    pub run_wrapper: Option<String>,
475    /// Extra paths to append to default lint commands (format, check, typecheck).
476    /// Ignored when project_file is set.
477    #[serde(default)]
478    pub extra_lint_paths: Vec<String>,
479    /// Project file for Maven/Gradle (e.g., "pom.xml", "build.gradle"). When set, default
480    /// lint/build/test commands target this file instead of the output directory.
481    #[serde(default)]
482    pub project_file: Option<String>,
483}
484
485fn default_java_ffi_style() -> String {
486    "panama".to_string()
487}
488
489/// Target platform for Kotlin code generation.
490///
491/// - `"jvm"` (default): emits source consuming the Java/Panama FFM facade.
492/// - `"native"`: emits Kotlin/Native source consuming the cbindgen C FFI library.
493/// - `"multiplatform"`: reserved for the KMP stage (Phase 3 follow-up).
494#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
495#[serde(rename_all = "lowercase")]
496pub enum KotlinTarget {
497    #[default]
498    Jvm,
499    Native,
500    // Multiplatform — Phase 3 KMP stage; placeholder so the enum is forward-compatible.
501    Multiplatform,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct KotlinConfig {
506    pub package: Option<String>,
507    #[serde(default)]
508    pub features: Option<Vec<String>>,
509    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
510    /// When set, this takes priority over the IR type-level serde_rename_all.
511    #[serde(default)]
512    pub serde_rename_all: Option<String>,
513    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
514    /// desired binding field name. Applied after automatic keyword escaping.
515    #[serde(default)]
516    pub rename_fields: HashMap<String, String>,
517    /// Functions to exclude from Kotlin binding generation.
518    #[serde(default)]
519    pub exclude_functions: Vec<String>,
520    /// Types to exclude from Kotlin binding generation.
521    #[serde(default)]
522    pub exclude_types: Vec<String>,
523    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
524    /// commands across all pipelines (lint, test, build, etc.).
525    #[serde(default)]
526    pub run_wrapper: Option<String>,
527    /// Extra paths to append to default lint commands (format, check, typecheck).
528    #[serde(default)]
529    pub extra_lint_paths: Vec<String>,
530    /// Target platform for Kotlin output. `"jvm"` (default) emits source consuming
531    /// the Java/Panama FFM facade; `"native"` emits Kotlin/Native source consuming
532    /// the cbindgen C FFI library. `"multiplatform"` is reserved for the KMP stage.
533    #[serde(default)]
534    pub target: KotlinTarget,
535    /// Emission mode controlling which Kotlin project layout is generated.
536    ///
537    /// Accepted values:
538    /// - `"jvm"` (default) — standard JVM-only project under `packages/kotlin/`
539    /// - `"kmp"` — Kotlin Multiplatform project under `packages/kotlin-mpp/`
540    /// - `"android"` — Android library project under `packages/kotlin-android/`
541    ///
542    /// When `None`, defaults to `"jvm"`.
543    #[serde(default)]
544    pub mode: Option<String>,
545}
546
547/// Dart bridging style: FRB (default) or raw `dart:ffi`.
548#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
549#[serde(rename_all = "lowercase")]
550pub enum DartStyle {
551    /// flutter_rust_bridge — emits a Rust crate plus Dart wrappers using
552    /// FRB-generated bridge symbols. Default.
553    #[default]
554    Frb,
555    /// Raw `dart:ffi` over the cbindgen C ABI — emits Dart-only source that
556    /// loads the shared library at runtime. Cheaper to ship; loses FRB's
557    /// async ergonomics and freezed-style data classes.
558    Ffi,
559}
560
561#[derive(Debug, Clone, Default, Serialize, Deserialize)]
562pub struct DartConfig {
563    /// Dart pub.dev package name (e.g. `"my_package"`). Used as the `name` in
564    /// `pubspec.yaml`. Defaults to a snake_case derivation of the crate name.
565    #[serde(default)]
566    pub pubspec_name: Option<String>,
567    /// Dart library name (the `library` declaration). Defaults to the pubspec name.
568    #[serde(default)]
569    pub lib_name: Option<String>,
570    /// Dart package name override (e.g. for pub.dev scoped packages).
571    #[serde(default)]
572    pub package_name: Option<String>,
573    /// Bridging style. `"frb"` (default) uses flutter_rust_bridge; `"ffi"` emits
574    /// raw `dart:ffi` source over the cbindgen C library.
575    #[serde(default)]
576    pub style: DartStyle,
577    /// flutter_rust_bridge version to pin in generated pubspec.yaml.
578    /// Defaults to `template_versions::cargo::FLUTTER_RUST_BRIDGE` when unset.
579    #[serde(default)]
580    pub frb_version: Option<String>,
581    /// Cargo features to enable on the binding crate.
582    #[serde(default)]
583    pub features: Option<Vec<String>>,
584    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
585    #[serde(default)]
586    pub serde_rename_all: Option<String>,
587    /// Per-field name remapping. Key is `TypeName.field_name`, value is the
588    /// desired binding field name. Applied after automatic keyword escaping.
589    #[serde(default)]
590    pub rename_fields: HashMap<String, String>,
591    /// Functions to exclude from Dart binding generation.
592    #[serde(default)]
593    pub exclude_functions: Vec<String>,
594    /// Types to exclude from Dart binding generation.
595    #[serde(default)]
596    pub exclude_types: Vec<String>,
597    /// Prefix wrapper for default tool invocations.
598    #[serde(default)]
599    pub run_wrapper: Option<String>,
600    /// Extra paths to append to default lint commands.
601    #[serde(default)]
602    pub extra_lint_paths: Vec<String>,
603    /// Override the core Cargo dependency name and path for the Dart binding crate.
604    /// When set, the binding `Cargo.toml` depends on this crate (resolved as
605    /// `../../../crates/<override>`) instead of the umbrella `[crate.name]`.
606    /// Defaults to unset.
607    #[serde(default)]
608    pub core_crate_override: Option<String>,
609    /// Keys to subtract from the merged `extra_dependencies` set for this
610    /// language only.
611    #[serde(default)]
612    pub exclude_extra_dependencies: Vec<String>,
613    /// Method names whose Rust bridge body should be emitted as `unimplemented!()`.
614    ///
615    /// Use this when a function's FFI signature (e.g. nested tuples containing
616    /// `Vec<u8>`) cannot be represented across the FRB bridge at all. Consumers must
617    /// list the method names explicitly — this field has no built-in defaults so the
618    /// knob is library-agnostic.
619    ///
620    /// Example (`alef.toml`):
621    /// ```toml
622    /// [crates.dart]
623    /// stub_methods = ["batch_extract_bytes", "batch_extract_bytes_sync"]
624    /// ```
625    #[serde(default)]
626    pub stub_methods: Vec<String>,
627}
628
629#[derive(Debug, Clone, Default, Serialize, Deserialize)]
630pub struct SwiftConfig {
631    /// Swift module name (e.g. `"MyLibrary"`). Defaults to PascalCase of the crate name.
632    #[serde(default)]
633    pub module_name: Option<String>,
634    /// Swift package name. Defaults to the module name.
635    #[serde(default)]
636    pub package_name: Option<String>,
637    /// swift-bridge version. Defaults to `template_versions::cargo::SWIFT_BRIDGE` when unset.
638    #[serde(default)]
639    pub swift_bridge_version: Option<String>,
640    /// Minimum macOS deployment target. Defaults to `template_versions::toolchain::SWIFT_MIN_MACOS` when unset.
641    #[serde(default)]
642    pub min_macos_version: Option<String>,
643    /// Minimum iOS deployment target. Defaults to `template_versions::toolchain::SWIFT_MIN_IOS` when unset.
644    #[serde(default)]
645    pub min_ios_version: Option<String>,
646    /// Cargo features to enable on the binding crate.
647    #[serde(default)]
648    pub features: Option<Vec<String>>,
649    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
650    #[serde(default)]
651    pub serde_rename_all: Option<String>,
652    /// Per-field name remapping. Key is `TypeName.field_name`, value is the
653    /// desired binding field name. Applied after automatic keyword escaping.
654    #[serde(default)]
655    pub rename_fields: HashMap<String, String>,
656    /// Functions to exclude from Swift binding generation.
657    #[serde(default)]
658    pub exclude_functions: Vec<String>,
659    /// Types to exclude from Swift binding generation.
660    #[serde(default)]
661    pub exclude_types: Vec<String>,
662    /// Fields to exclude from Swift binding generation.
663    /// Format: `"TypeName.field_name"`.
664    #[serde(default)]
665    pub exclude_fields: Vec<String>,
666    /// Prefix wrapper for default tool invocations.
667    #[serde(default)]
668    pub run_wrapper: Option<String>,
669    /// Extra paths to append to default lint commands.
670    #[serde(default)]
671    pub extra_lint_paths: Vec<String>,
672    /// Override the core Cargo dependency name and path for the Swift binding crate.
673    /// When set, the binding `Cargo.toml` depends on this crate (resolved as
674    /// `../../../crates/<override>`) instead of the umbrella `[crate.name]`.
675    /// Defaults to unset.
676    #[serde(default)]
677    pub core_crate_override: Option<String>,
678    /// Keys to subtract from the merged `extra_dependencies` set for this
679    /// language only.
680    #[serde(default)]
681    pub exclude_extra_dependencies: Vec<String>,
682    /// Override the auto-generated `create_<type>(api_key, base_url)` constructor
683    /// body for opaque client types that expose methods. When set, the swift backend
684    /// emits this snippet verbatim as the function body (no implicit `Ok(...)`).
685    ///
686    /// Use this when the source crate's constructor signature differs from the
687    /// default `Type::new(api_key, base_url)` shape — e.g. liter-llm uses
688    /// `DefaultClient::new(ClientConfig, Option<&str>)` and needs to build a
689    /// `ClientConfig` from the bridge inputs first.
690    ///
691    /// The snippet is parameterised by `{type_name}` (the wrapper newtype name)
692    /// and runs in a function body with `api_key: String` and `base_url: Option<String>`
693    /// already in scope. It must return `Result<{type_name}, String>`.
694    #[serde(default)]
695    pub client_constructor_body: HashMap<String, String>,
696}
697
698#[derive(Debug, Clone, Serialize, Deserialize)]
699pub struct GleamConfig {
700    pub app_name: Option<String>,
701    /// Erlang atom name for @external(erlang, "<nif>", ...) lookups (e.g., "my_app_nif").
702    /// Defaults to the app_name.
703    #[serde(default)]
704    pub nif_module: Option<String>,
705    #[serde(default)]
706    pub features: Option<Vec<String>>,
707    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
708    /// When set, this takes priority over the IR type-level serde_rename_all.
709    #[serde(default)]
710    pub serde_rename_all: Option<String>,
711    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
712    /// desired binding field name. Applied after automatic keyword escaping.
713    #[serde(default)]
714    pub rename_fields: HashMap<String, String>,
715    /// Functions to exclude from Gleam binding generation.
716    #[serde(default)]
717    pub exclude_functions: Vec<String>,
718    /// Types to exclude from Gleam binding generation.
719    #[serde(default)]
720    pub exclude_types: Vec<String>,
721    /// Prefix wrapper for default tool invocations.
722    #[serde(default)]
723    pub run_wrapper: Option<String>,
724    /// Extra paths to append to default lint commands.
725    #[serde(default)]
726    pub extra_lint_paths: Vec<String>,
727    /// Per-`element_type` Gleam record-constructor recipes used by the e2e
728    /// generator when emitting `json_object` arg literals. Each entry maps a
729    /// fixture-side `element_type` string (e.g. `"BatchFileItem"`) to a
730    /// structured constructor description that the codegen interpolates per
731    /// JSON-array item. Without an entry the codegen falls back to the
732    /// `json_object_wrapper` (or a plain `json_to_gleam`).
733    ///
734    /// Example:
735    ///
736    /// ```toml
737    /// [[crates.gleam.element_constructors]]
738    /// element_type = "BatchFileItem"
739    /// constructor = "kreuzberg.BatchFileItem"
740    /// [[crates.gleam.element_constructors.fields]]
741    /// gleam_field = "path"
742    /// kind = "file_path"
743    /// json_field = "path"
744    /// [[crates.gleam.element_constructors.fields]]
745    /// gleam_field = "config"
746    /// kind = "literal"
747    /// value = "option.None"
748    /// ```
749    #[serde(default)]
750    pub element_constructors: Vec<GleamElementConstructor>,
751    /// Optional Gleam expression template used to wrap `json_object` arg
752    /// values when no `element_type` recipe matches. The placeholder
753    /// `{json}` is replaced with a Gleam string literal containing the JSON
754    /// form of the arg value, allowing the downstream's Gleam binding to do
755    /// its own parsing.
756    ///
757    /// Example:
758    ///
759    /// ```toml
760    /// [crates.gleam]
761    /// json_object_wrapper = "kreuzberg.config_from_json_string({json})"
762    /// ```
763    ///
764    /// When `None`, the codegen emits `{json}` verbatim (a plain Gleam
765    /// string), matching the iter15 default.
766    #[serde(default)]
767    pub json_object_wrapper: Option<String>,
768}
769
770/// One per-`element_type` Gleam record-constructor recipe. Keyed by the
771/// fixture-side `element_type` string and consumed by the e2e Gleam codegen
772/// when building `json_object` arg literals.
773#[derive(Debug, Clone, Serialize, Deserialize)]
774pub struct GleamElementConstructor {
775    /// Fixture-side `element_type` value this recipe applies to (e.g.
776    /// `"BatchFileItem"`).
777    pub element_type: String,
778    /// Fully-qualified Gleam constructor identifier (e.g.
779    /// `"kreuzberg.BatchFileItem"`). Emitted verbatim before the `(...)` field
780    /// list.
781    pub constructor: String,
782    /// Ordered list of fields to emit inside the constructor's `(...)` block,
783    /// in argument-position order. Each field describes how its value is
784    /// derived from the per-item JSON object.
785    pub fields: Vec<GleamElementField>,
786}
787
788/// One field inside a [`GleamElementConstructor`]'s argument list.
789///
790/// `kind` selects the source/encoding strategy:
791/// * `"file_path"` — read `json_field` from the JSON object as a string,
792///   prefix with the configured `test_documents_dir` when the value does not
793///   start with `/`, and emit as a Gleam string literal.
794/// * `"byte_array"` — read `json_field` from the JSON object as a JSON
795///   `Array(Number)` and emit as a Gleam BitArray literal `<<n1, n2, …>>`.
796/// * `"string"` — read `json_field` as a string, emit as a Gleam string
797///   literal; falls back to `default` (or empty) if missing.
798/// * `"literal"` — emit `value` verbatim (no JSON lookup). Use for
799///   constant fields like `config: option.None`.
800#[derive(Debug, Clone, Serialize, Deserialize)]
801pub struct GleamElementField {
802    /// Gleam record field name (e.g. `"path"`, `"config"`).
803    pub gleam_field: String,
804    /// Source/encoding strategy. See struct doc.
805    pub kind: String,
806    /// JSON object key to read, when `kind` is one of the JSON-driven
807    /// strategies. Required for `"file_path"`, `"byte_array"`, `"string"`;
808    /// ignored for `"literal"`.
809    #[serde(default)]
810    pub json_field: Option<String>,
811    /// Default Gleam expression when `json_field` is missing/null. Only
812    /// honoured by the `"string"` strategy today.
813    #[serde(default)]
814    pub default: Option<String>,
815    /// Verbatim Gleam expression to emit when `kind = "literal"`.
816    #[serde(default)]
817    pub value: Option<String>,
818}
819
820#[derive(Debug, Clone, Serialize, Deserialize)]
821pub struct ZigConfig {
822    pub module_name: Option<String>,
823    #[serde(default)]
824    pub features: Option<Vec<String>>,
825    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
826    /// When set, this takes priority over the IR type-level serde_rename_all.
827    #[serde(default)]
828    pub serde_rename_all: Option<String>,
829    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
830    /// desired binding field name. Applied after automatic keyword escaping.
831    #[serde(default)]
832    pub rename_fields: HashMap<String, String>,
833    /// Functions to exclude from Zig binding generation.
834    #[serde(default)]
835    pub exclude_functions: Vec<String>,
836    /// Types to exclude from Zig binding generation.
837    #[serde(default)]
838    pub exclude_types: Vec<String>,
839    /// Prefix wrapper for default tool invocations.
840    #[serde(default)]
841    pub run_wrapper: Option<String>,
842    /// Extra paths to append to default lint commands.
843    #[serde(default)]
844    pub extra_lint_paths: Vec<String>,
845}
846
847#[derive(Debug, Clone, Serialize, Deserialize)]
848pub struct CSharpConfig {
849    pub namespace: Option<String>,
850    /// NuGet `<PackageId>` to publish under. When unset, falls back to `namespace`.
851    /// Use this when the published artifact id must differ from the C# `RootNamespace` —
852    /// e.g. when the unprefixed name is owned by a third party on nuget.org and
853    /// you publish under a vendor-prefixed id like `KreuzbergDev.<Lib>`.
854    #[serde(default)]
855    pub package_id: Option<String>,
856    pub target_framework: Option<String>,
857    #[serde(default)]
858    pub features: Option<Vec<String>>,
859    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
860    /// When set, this takes priority over the IR type-level serde_rename_all.
861    #[serde(default)]
862    pub serde_rename_all: Option<String>,
863    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
864    /// desired binding field name. Applied after automatic keyword escaping.
865    #[serde(default)]
866    pub rename_fields: HashMap<String, String>,
867    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
868    /// commands across all pipelines (lint, test, build, etc.).
869    #[serde(default)]
870    pub run_wrapper: Option<String>,
871    /// Extra paths to append to default lint commands (format, check, typecheck).
872    /// Ignored when project_file is set.
873    #[serde(default)]
874    pub extra_lint_paths: Vec<String>,
875    /// Project file for C# (e.g., "MyProject.csproj", "MySolution.sln"). When set, default
876    /// lint/build/test commands target this file instead of the output directory.
877    #[serde(default)]
878    pub project_file: Option<String>,
879    /// Functions to exclude from C# binding generation (e.g., functions not present in the
880    /// C FFI layer). Excluded functions are omitted from both NativeMethods.cs and the
881    /// wrapper class.
882    #[serde(default)]
883    pub exclude_functions: Vec<String>,
884}
885
886#[derive(Debug, Clone, Serialize, Deserialize)]
887pub struct RConfig {
888    pub package_name: Option<String>,
889    #[serde(default)]
890    pub features: Option<Vec<String>>,
891    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
892    /// When set, this takes priority over the IR type-level serde_rename_all.
893    #[serde(default)]
894    pub serde_rename_all: Option<String>,
895    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
896    /// desired binding field name. Applied after automatic keyword escaping.
897    #[serde(default)]
898    pub rename_fields: HashMap<String, String>,
899    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
900    /// commands across all pipelines (lint, test, build, etc.).
901    #[serde(default)]
902    pub run_wrapper: Option<String>,
903    /// Extra paths to append to default lint commands (format, check, typecheck).
904    #[serde(default)]
905    pub extra_lint_paths: Vec<String>,
906}
907
908/// Custom modules that alef should declare (mod X;) but not generate.
909/// These are hand-written modules imported by the generated lib.rs.
910#[derive(Debug, Clone, Default, Serialize, Deserialize)]
911pub struct CustomModulesConfig {
912    #[serde(default)]
913    pub python: Vec<String>,
914    #[serde(default)]
915    pub node: Vec<String>,
916    #[serde(default)]
917    pub ruby: Vec<String>,
918    #[serde(default)]
919    pub php: Vec<String>,
920    #[serde(default)]
921    pub elixir: Vec<String>,
922    #[serde(default)]
923    pub wasm: Vec<String>,
924    #[serde(default)]
925    pub ffi: Vec<String>,
926    #[serde(default)]
927    pub go: Vec<String>,
928    #[serde(default)]
929    pub java: Vec<String>,
930    #[serde(default)]
931    pub csharp: Vec<String>,
932    #[serde(default)]
933    pub r: Vec<String>,
934}
935
936impl CustomModulesConfig {
937    pub fn for_language(&self, lang: Language) -> &[String] {
938        match lang {
939            Language::Python => &self.python,
940            Language::Node => &self.node,
941            Language::Ruby => &self.ruby,
942            Language::Php => &self.php,
943            Language::Elixir => &self.elixir,
944            Language::Wasm => &self.wasm,
945            Language::Ffi => &self.ffi,
946            Language::Go => &self.go,
947            Language::Java => &self.java,
948            Language::Csharp => &self.csharp,
949            Language::R => &self.r,
950            Language::Rust => &[], // Rust doesn't need custom modules (no binding crate)
951            Language::Kotlin | Language::Swift | Language::Dart | Language::Gleam | Language::Zig | Language::C => &[],
952        }
953    }
954}
955
956/// Custom classes/functions from hand-written modules to register in module init.
957#[derive(Debug, Clone, Default, Serialize, Deserialize)]
958pub struct CustomRegistration {
959    #[serde(default)]
960    pub classes: Vec<String>,
961    #[serde(default)]
962    pub functions: Vec<String>,
963    #[serde(default)]
964    pub init_calls: Vec<String>,
965}
966
967/// Per-language custom registrations.
968#[derive(Debug, Clone, Default, Serialize, Deserialize)]
969pub struct CustomRegistrationsConfig {
970    #[serde(default)]
971    pub python: Option<CustomRegistration>,
972    #[serde(default)]
973    pub node: Option<CustomRegistration>,
974    #[serde(default)]
975    pub ruby: Option<CustomRegistration>,
976    #[serde(default)]
977    pub php: Option<CustomRegistration>,
978    #[serde(default)]
979    pub elixir: Option<CustomRegistration>,
980    #[serde(default)]
981    pub wasm: Option<CustomRegistration>,
982}
983
984impl CustomRegistrationsConfig {
985    pub fn for_language(&self, lang: Language) -> Option<&CustomRegistration> {
986        match lang {
987            Language::Python => self.python.as_ref(),
988            Language::Node => self.node.as_ref(),
989            Language::Ruby => self.ruby.as_ref(),
990            Language::Php => self.php.as_ref(),
991            Language::Elixir => self.elixir.as_ref(),
992            Language::Wasm => self.wasm.as_ref(),
993            _ => None,
994        }
995    }
996}