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    /// Runtime Python (PyPI) dependencies emitted into `[project] dependencies`
95    /// of the scaffold-generated `pyproject.toml`. Entries are PEP 508 strings
96    /// such as `"tree-sitter>=0.23"` and pass through verbatim. Empty by default.
97    #[serde(default)]
98    pub pip_dependencies: Vec<String>,
99    /// Override the scaffold output directory for this language's Cargo.toml and package files.
100    #[serde(default)]
101    pub scaffold_output: Option<PathBuf>,
102    /// Per-field name remapping for this language. Key is `TypeName.field_name` (e.g.
103    /// `"LayoutDetection.class"`), value is the desired binding field name. Applied after
104    /// automatic keyword escaping, so an explicit entry takes priority.
105    #[serde(default)]
106    pub rename_fields: HashMap<String, String>,
107    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
108    /// commands across all pipelines (lint, test, build, etc.).
109    /// E.g., `run_wrapper = "uv run --no-sync"` turns `ruff format packages/python` into
110    /// `uv run --no-sync ruff format packages/python`.
111    #[serde(default)]
112    pub run_wrapper: Option<String>,
113    /// Extra paths to append to default lint commands (format, check, typecheck).
114    /// Space-separated paths are appended to the command.
115    #[serde(default)]
116    pub extra_lint_paths: Vec<String>,
117    /// Additional `from <module> import <symbol>` lines to emit in the generated `__init__.py`.
118    /// Key is the relative or absolute Python module path (e.g. `"._supported_languages"`),
119    /// value is the list of symbols to import. The symbols are also added to `__all__`.
120    ///
121    /// Use this to re-export hand-written sibling modules (e.g. generated by a project's own
122    /// build script) without alef's cleanup culling them. The hand-written file must NOT contain
123    /// the substrings `"DO NOT EDIT"`, `"auto-generated by alef"`, or `"AUTO-GENERATED by alef"`
124    /// in its first 5 lines, or alef's cleanup pipeline will treat it as a stale alef artifact.
125    #[serde(default)]
126    pub extra_init_imports: std::collections::BTreeMap<String, Vec<String>>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct StubsConfig {
131    pub output: PathBuf,
132}
133
134/// Configuration for a single capsule type entry in `NodeConfig::capsule_types`.
135///
136/// When set, the named Rust type is NOT emitted as a `#[napi]` opaque wrapper.
137/// Instead, functions returning this type produce a `JsObject` carrying the raw
138/// pointer in a configurable `Napi::External<T>` property — the layout consumed
139/// by the `tree-sitter` npm package's `Parser.setLanguage()`.
140///
141/// TOML form:
142/// ```toml
143/// [crates.node.capsule_types.Language]
144/// type = "Language"
145/// from_module = "tree-sitter"
146/// property_name = "language"
147/// type_tag = { lower = "0x8AF2E5212AD58ABF", upper = "0xD5006CAD83ABBA16" }
148/// ```
149#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
150pub struct NodeCapsuleTypeConfig {
151    /// User-facing class name in the ecosystem library (e.g. `"Language"`).
152    /// Emitted as the return-type annotation in the generated `index.d.ts`.
153    #[serde(rename = "type")]
154    pub type_name: String,
155    /// npm package to import the type from (e.g. `"tree-sitter"`).
156    /// Emitted as the `from` clause in the generated `import type` line.
157    pub from_module: String,
158    /// Codegen strategy. Currently only `"external_pointer"` is supported.
159    /// Defaults to `"external_pointer"`.
160    #[serde(default = "default_node_capsule_construct")]
161    pub construct: String,
162    /// JS property name to set on the returned object. `node-tree-sitter`
163    /// reads `value["language"]`; other consumers may use different names.
164    /// Defaults to `"__parser"` for back-compat with existing configs.
165    #[serde(default = "default_node_capsule_property_name")]
166    pub property_name: String,
167    /// Optional N-API type tag to apply via `napi_type_tag_object`. Required
168    /// when the consumer library (e.g. `node-tree-sitter`) calls
169    /// `napi_check_object_type_tag` to validate the External before using it.
170    #[serde(default)]
171    pub type_tag: Option<NapiTypeTagConfig>,
172}
173
174/// An N-API `napi_type_tag` value, expressed as two 64-bit hex strings.
175#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
176pub struct NapiTypeTagConfig {
177    /// Lower 64 bits of the tag, hex (e.g. `"0x8AF2E5212AD58ABF"`).
178    pub lower: String,
179    /// Upper 64 bits of the tag, hex (e.g. `"0xD5006CAD83ABBA16"`).
180    pub upper: String,
181}
182
183fn default_node_capsule_construct() -> String {
184    "external_pointer".to_string()
185}
186
187fn default_node_capsule_property_name() -> String {
188    "__parser".to_string()
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct NodeConfig {
193    pub package_name: Option<String>,
194    /// Per-language feature override. When set, these features are used instead of
195    /// `[crate] features` for this language's binding crate.
196    #[serde(default)]
197    pub features: Option<Vec<String>>,
198    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
199    /// When set, this takes priority over the IR type-level serde_rename_all.
200    #[serde(default)]
201    pub serde_rename_all: Option<String>,
202    /// Prefix for generated type names (e.g. "Js" produces `JsConversionOptions`).
203    /// Defaults to `"Js"`.
204    #[serde(default)]
205    pub type_prefix: Option<String>,
206    /// Map of Rust type name -> capsule config for raw-pointer passthrough.
207    /// Types listed here skip the default `#[napi]` opaque-wrapper emission;
208    /// functions returning them produce a `JsObject` with a `__parser`
209    /// `Napi::External<T>` property instead. See [`NodeCapsuleTypeConfig`].
210    #[serde(default)]
211    pub capsule_types: HashMap<String, NodeCapsuleTypeConfig>,
212    /// Functions to exclude from Node binding generation.
213    #[serde(default)]
214    pub exclude_functions: Vec<String>,
215    /// Types to exclude from Node binding generation.
216    #[serde(default)]
217    pub exclude_types: Vec<String>,
218    /// Additional Cargo dependencies for this language's binding crate only.
219    #[serde(default)]
220    pub extra_dependencies: HashMap<String, toml::Value>,
221    /// Override the scaffold output directory for this language's Cargo.toml and package files.
222    #[serde(default)]
223    pub scaffold_output: Option<PathBuf>,
224    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
225    /// desired binding field name. Applied after automatic keyword escaping.
226    #[serde(default)]
227    pub rename_fields: HashMap<String, String>,
228    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
229    /// commands across all pipelines (lint, test, build, etc.).
230    #[serde(default)]
231    pub run_wrapper: Option<String>,
232    /// Extra paths to append to default lint commands (format, check, typecheck).
233    #[serde(default)]
234    pub extra_lint_paths: Vec<String>,
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct RubyConfig {
239    pub gem_name: Option<String>,
240    pub stubs: Option<StubsConfig>,
241    /// Per-language feature override. When set, these features are used instead of
242    /// `[crate] features` for this language's binding crate.
243    #[serde(default)]
244    pub features: Option<Vec<String>>,
245    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
246    /// When set, this takes priority over the IR type-level serde_rename_all.
247    #[serde(default)]
248    pub serde_rename_all: Option<String>,
249    /// Functions to exclude from Ruby binding generation.
250    #[serde(default)]
251    pub exclude_functions: Vec<String>,
252    /// Types to exclude from Ruby binding generation.
253    #[serde(default)]
254    pub exclude_types: Vec<String>,
255    /// Additional Cargo dependencies for this language's binding crate only.
256    #[serde(default)]
257    pub extra_dependencies: HashMap<String, toml::Value>,
258    /// Override the scaffold output directory for this language's Cargo.toml and package files.
259    #[serde(default)]
260    pub scaffold_output: Option<PathBuf>,
261    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
262    /// desired binding field name. Applied after automatic keyword escaping.
263    #[serde(default)]
264    pub rename_fields: HashMap<String, String>,
265    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
266    /// commands across all pipelines (lint, test, build, etc.).
267    #[serde(default)]
268    pub run_wrapper: Option<String>,
269    /// Extra paths to append to default lint commands (format, check, typecheck).
270    #[serde(default)]
271    pub extra_lint_paths: Vec<String>,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct PhpConfig {
276    pub extension_name: Option<String>,
277    /// Cargo crate name for the PHP binding (e.g. `"ts-pack-core-php"`).
278    /// Used to derive the shared library filename in the e2e test runner.
279    /// When absent, the lib name is derived from `extension_name` by appending `_php`.
280    #[serde(default)]
281    pub cargo_crate_name: Option<String>,
282    /// Override the PHP namespace used for class registration and PSR-4 autoloading.
283    ///
284    /// When set, this value is used verbatim as the PHP namespace (e.g. `"HtmlToMarkdown"`).
285    /// When absent, the namespace is derived from `extension_name` by splitting on `_` and
286    /// converting each segment to PascalCase (e.g. `html_to_markdown` → `Html\To\Markdown`).
287    #[serde(default)]
288    pub namespace: Option<String>,
289    /// Feature gate for ext-php-rs (default: "extension-module").
290    /// All generated code is wrapped in `#[cfg(feature = "...")]`.
291    #[serde(default)]
292    pub feature_gate: Option<String>,
293    /// Output directory for generated PHP facade / stubs (e.g., `packages/php/src/`).
294    #[serde(default)]
295    pub stubs: Option<StubsConfig>,
296    #[serde(default)]
297    pub features: Option<Vec<String>>,
298    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
299    /// When set, this takes priority over the IR type-level serde_rename_all.
300    #[serde(default)]
301    pub serde_rename_all: Option<String>,
302    /// Functions to exclude from PHP binding generation.
303    #[serde(default)]
304    pub exclude_functions: Vec<String>,
305    /// Types to exclude from PHP binding generation.
306    #[serde(default)]
307    pub exclude_types: Vec<String>,
308    /// Additional Cargo dependencies for this language's binding crate only.
309    #[serde(default)]
310    pub extra_dependencies: HashMap<String, toml::Value>,
311    /// Override the scaffold output directory for this language's Cargo.toml and package files.
312    #[serde(default)]
313    pub scaffold_output: Option<PathBuf>,
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    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
319    /// commands across all pipelines (lint, test, build, etc.).
320    #[serde(default)]
321    pub run_wrapper: Option<String>,
322    /// Extra paths to append to default lint commands (format, check, typecheck).
323    #[serde(default)]
324    pub extra_lint_paths: Vec<String>,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct ElixirConfig {
329    pub app_name: Option<String>,
330    #[serde(default)]
331    pub features: Option<Vec<String>>,
332    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
333    /// When set, this takes priority over the IR type-level serde_rename_all.
334    #[serde(default)]
335    pub serde_rename_all: Option<String>,
336    /// Functions to exclude from Elixir NIF generation.
337    #[serde(default)]
338    pub exclude_functions: Vec<String>,
339    /// Types to exclude from Elixir NIF generation.
340    #[serde(default)]
341    pub exclude_types: Vec<String>,
342    /// Additional Cargo dependencies for this language's binding crate only.
343    #[serde(default)]
344    pub extra_dependencies: HashMap<String, toml::Value>,
345    /// Override the scaffold output directory for this language's Cargo.toml and package files.
346    #[serde(default)]
347    pub scaffold_output: Option<PathBuf>,
348    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
349    /// desired binding field name. Applied after automatic keyword escaping.
350    #[serde(default)]
351    pub rename_fields: HashMap<String, String>,
352    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
353    /// commands across all pipelines (lint, test, build, etc.).
354    #[serde(default)]
355    pub run_wrapper: Option<String>,
356    /// Extra paths to append to default lint commands (format, check, typecheck).
357    #[serde(default)]
358    pub extra_lint_paths: Vec<String>,
359    /// Functions that should be scheduled on the dirty CPU scheduler.
360    /// HTML parsing and other CPU-intensive NIFs should be listed here to avoid
361    /// blocking BEAM scheduler threads.
362    #[serde(default)]
363    pub cpu_bound_functions: Vec<String>,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct WasmConfig {
368    #[serde(default)]
369    pub exclude_functions: Vec<String>,
370    #[serde(default)]
371    pub exclude_types: Vec<String>,
372    #[serde(default)]
373    pub type_overrides: HashMap<String, String>,
374    #[serde(default)]
375    pub features: Option<Vec<String>>,
376    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
377    /// When set, this takes priority over the IR type-level serde_rename_all.
378    #[serde(default)]
379    pub serde_rename_all: Option<String>,
380    /// Prefix for generated type names (e.g. "Wasm" produces `WasmConversionOptions`).
381    /// Defaults to `"Wasm"`.
382    #[serde(default)]
383    pub type_prefix: Option<String>,
384    /// Functions to exclude from the public TypeScript re-export (index.ts) while still
385    /// generating the Rust binding. Use this when a custom module provides a wrapper.
386    #[serde(default)]
387    pub exclude_reexports: Vec<String>,
388    /// Wide-character C functions to shim for WASM external scanner interop.
389    #[serde(default)]
390    pub env_shims: Vec<String>,
391    /// Additional Cargo dependencies for the WASM binding crate only.
392    #[serde(default)]
393    pub extra_dependencies: HashMap<String, toml::Value>,
394    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
395    /// desired binding field name. Applied after automatic keyword escaping.
396    #[serde(default)]
397    pub rename_fields: HashMap<String, String>,
398    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
399    /// commands across all pipelines (lint, test, build, etc.).
400    #[serde(default)]
401    pub run_wrapper: Option<String>,
402    /// Extra paths to append to default lint commands (format, check, typecheck).
403    #[serde(default)]
404    pub extra_lint_paths: Vec<String>,
405    /// Override the core Cargo dependency name and path for the WASM binding crate.
406    /// When set, the binding `Cargo.toml` depends on this crate (resolved as
407    /// `../<override>`) instead of the umbrella `[crate.name]`. Use this to point
408    /// the WASM binding at a wasm-safe sub-crate while other languages keep the
409    /// facade. Defaults to unset.
410    #[serde(default)]
411    pub core_crate_override: Option<String>,
412    /// Keys to subtract from the merged `extra_dependencies` set for this
413    /// language only. Useful when `[crate.extra_dependencies]` lists sibling
414    /// crates that the WASM target cannot link.
415    #[serde(default)]
416    pub exclude_extra_dependencies: Vec<String>,
417    /// Hand-written Rust modules to declare in the generated lib.rs with `pub mod <name>;`
418    /// and re-export with `pub use <name>::*;`. Separate from `[custom_modules].wasm` which
419    /// only adds TypeScript `export *` re-exports. Use this for Rust-side dispatch/glue modules.
420    #[serde(default)]
421    pub custom_rust_modules: Vec<String>,
422    /// Per-type field exclusions for the generated From impls and binding struct.
423    /// Key is the type name (e.g. "ServerConfig"), value is a list of field names to skip.
424    /// Use when source fields are gated behind `#[cfg(not(target_arch = "wasm32"))]` and
425    /// therefore don't exist in the wasm32 compilation environment.
426    #[serde(default)]
427    pub exclude_fields: HashMap<String, Vec<String>>,
428    /// Source crate names whose types are re-exported by the `core_crate_override`
429    /// crate. References to `<original_crate>::TypeName` in generated code are
430    /// rewritten to `<override_crate>::TypeName`. Only meaningful when
431    /// `core_crate_override` is set.
432    /// Example: with `core_crate_override = "mylib-http"`, setting
433    /// `source_crate_remaps = ["mylib-core", "mylib"]` rewrites
434    /// `mylib_core::Method` and `mylib::Method` references to
435    /// `mylib_http::Method` (assumes `mylib-http` re-exports them via
436    /// `pub use mylib_core::*`).
437    #[serde(default)]
438    pub source_crate_remaps: Vec<String>,
439}
440
441#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct FfiConfig {
443    pub prefix: Option<String>,
444    #[serde(default = "default_error_style")]
445    pub error_style: String,
446    pub header_name: Option<String>,
447    /// Native library name for Go cgo/Java Panama/C# P/Invoke (e.g., "ts_pack_ffi").
448    /// Defaults to `{prefix}_ffi`.
449    #[serde(default)]
450    pub lib_name: Option<String>,
451    /// If true, generate visitor/callback FFI support.
452    #[serde(default)]
453    pub visitor_callbacks: bool,
454    #[serde(default)]
455    pub features: Option<Vec<String>>,
456    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
457    /// When set, this takes priority over the IR type-level serde_rename_all.
458    #[serde(default)]
459    pub serde_rename_all: Option<String>,
460    /// Functions to exclude from FFI binding generation.
461    #[serde(default)]
462    pub exclude_functions: Vec<String>,
463    /// Types to exclude from FFI binding generation.
464    #[serde(default)]
465    pub exclude_types: Vec<String>,
466    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
467    /// desired binding field name. Applied after automatic keyword escaping.
468    #[serde(default)]
469    pub rename_fields: HashMap<String, String>,
470    /// Rust expression used to construct an error value of this crate's
471    /// `error_type` from a runtime `String` message inside generated FFI
472    /// trait-bridge plugin shims (`plugin_impl_initialize`, `plugin_impl_shutdown`).
473    ///
474    /// The expression has access to a local variable `msg: String` containing
475    /// the underlying error message and is interpolated verbatim. Example
476    /// values:
477    ///
478    /// ```toml
479    /// # downstream whose error type has a struct variant with two fields:
480    /// plugin_error_constructor = """
481    /// kreuzberg::KreuzbergError::Plugin { message: msg, plugin_name: String::new() }
482    /// """
483    ///
484    /// # downstream whose error type implements `From<String>`:
485    /// plugin_error_constructor = "MyError::from(msg)"
486    /// ```
487    ///
488    /// Defaults to `None`. When unset, the plugin shim still emits — backends
489    /// fall back to a `format!("{}: {}", prefix, msg)`-style construction via
490    /// the configured `error_constructor`. Downstreams that don't expose
491    /// trait-bridged plugins can ignore this knob entirely.
492    #[serde(default)]
493    pub plugin_error_constructor: Option<String>,
494}
495
496fn default_error_style() -> String {
497    "last_error".to_string()
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
501pub struct GoConfig {
502    pub module: Option<String>,
503    /// Override the Go package name (default: derived from module path)
504    pub package_name: Option<String>,
505    #[serde(default)]
506    pub features: Option<Vec<String>>,
507    /// Types to exclude from Go binding generation.
508    ///
509    /// Go bindings call the generated C FFI directly through cgo, so types excluded from
510    /// `[crates.ffi].exclude_types` are also excluded automatically by the Go backend.
511    #[serde(default)]
512    pub exclude_types: Vec<String>,
513    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
514    /// When set, this takes priority over the IR type-level serde_rename_all.
515    #[serde(default)]
516    pub serde_rename_all: Option<String>,
517    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
518    /// desired binding field name. Applied after automatic keyword escaping.
519    #[serde(default)]
520    pub rename_fields: HashMap<String, String>,
521    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
522    /// commands across all pipelines (lint, test, build, etc.).
523    #[serde(default)]
524    pub run_wrapper: Option<String>,
525    /// Extra paths to append to default lint commands (format, check, typecheck).
526    #[serde(default)]
527    pub extra_lint_paths: Vec<String>,
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize)]
531pub struct JavaConfig {
532    pub package: Option<String>,
533    /// Override the Maven `<groupId>` emitted by alef-scaffold and alef-e2e. When unset,
534    /// `java_group_id()` falls back to the Java `package` value. Set this when the
535    /// published Maven coords differ from the Java package path (e.g. group
536    /// `dev.kreuzberg`, package `dev.kreuzberg.htmltomarkdown`).
537    #[serde(default)]
538    pub group_id: Option<String>,
539    /// Override the Maven `<artifactId>` emitted by alef-scaffold and alef-e2e. When
540    /// unset, defaults to the crate name (the `[[crates]] name = "..."`). Set this when
541    /// the published artifactId differs from the source crate name (e.g. crate
542    /// `html-to-markdown-rs` published as `html-to-markdown`).
543    #[serde(default)]
544    pub artifact_id: Option<String>,
545    #[serde(default = "default_java_ffi_style")]
546    pub ffi_style: String,
547    #[serde(default)]
548    pub features: Option<Vec<String>>,
549    /// Types to exclude from Java binding generation.
550    ///
551    /// Java's Panama bindings call the generated C FFI directly, so types excluded from
552    /// `[crates.ffi].exclude_types` are also excluded automatically by the Java backend.
553    #[serde(default)]
554    pub exclude_types: Vec<String>,
555    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
556    /// When set, this takes priority over the IR type-level serde_rename_all.
557    #[serde(default)]
558    pub serde_rename_all: Option<String>,
559    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
560    /// desired binding field name. Applied after automatic keyword escaping.
561    #[serde(default)]
562    pub rename_fields: HashMap<String, String>,
563    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
564    /// commands across all pipelines (lint, test, build, etc.).
565    #[serde(default)]
566    pub run_wrapper: Option<String>,
567    /// Extra paths to append to default lint commands (format, check, typecheck).
568    /// Ignored when project_file is set.
569    #[serde(default)]
570    pub extra_lint_paths: Vec<String>,
571    /// Project file for Maven/Gradle (e.g., "pom.xml", "build.gradle"). When set, default
572    /// lint/build/test commands target this file instead of the output directory.
573    #[serde(default)]
574    pub project_file: Option<String>,
575}
576
577fn default_java_ffi_style() -> String {
578    "panama".to_string()
579}
580
581/// FFI strategy for Kotlin JVM / Android binding emission.
582///
583/// - `"panama"` (default): consumes the Java/Panama FFM facade emitted by
584///   `alef-backend-java`. Requires JDK 22+ at runtime. Not supported on
585///   Android Runtime.
586/// - `"jni"`: emits a `object <Module>Bridge { external fun native<...>(...) }`
587///   object with JNI declarations and a `DefaultClient` class holding a `Long`
588///   handle. Compatible with Android Runtime (JDK 11). Consumers must ship a
589///   `<crate>-jni` Rust crate exporting matching `Java_*` JNI symbols.
590#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
591#[serde(rename_all = "lowercase")]
592pub enum KotlinFfiStyle {
593    #[default]
594    Panama,
595    Jni,
596}
597
598/// Target platform for Kotlin code generation.
599///
600/// - `"jvm"` (default): emits source consuming the Java/Panama FFM facade.
601/// - `"native"`: emits Kotlin/Native source consuming the cbindgen C FFI library.
602/// - `"multiplatform"`: emits Kotlin Multiplatform project scaffolding.
603#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
604#[serde(rename_all = "lowercase")]
605pub enum KotlinTarget {
606    #[default]
607    Jvm,
608    Native,
609    // Multiplatform — Phase 3 KMP stage; placeholder so the enum is forward-compatible.
610    Multiplatform,
611}
612
613#[derive(Debug, Clone, Default, Serialize, Deserialize)]
614pub struct KotlinConfig {
615    pub package: Option<String>,
616    #[serde(default)]
617    pub features: Option<Vec<String>>,
618    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
619    /// When set, this takes priority over the IR type-level serde_rename_all.
620    #[serde(default)]
621    pub serde_rename_all: Option<String>,
622    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
623    /// desired binding field name. Applied after automatic keyword escaping.
624    #[serde(default)]
625    pub rename_fields: HashMap<String, String>,
626    /// Functions to exclude from Kotlin binding generation.
627    #[serde(default)]
628    pub exclude_functions: Vec<String>,
629    /// Types to exclude from Kotlin binding generation.
630    #[serde(default)]
631    pub exclude_types: Vec<String>,
632    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
633    /// commands across all pipelines (lint, test, build, etc.).
634    #[serde(default)]
635    pub run_wrapper: Option<String>,
636    /// Extra paths to append to default lint commands (format, check, typecheck).
637    #[serde(default)]
638    pub extra_lint_paths: Vec<String>,
639    /// Target platform for Kotlin output. `"jvm"` (default) emits source consuming
640    /// the Java/Panama FFM facade; `"native"` emits Kotlin/Native source consuming
641    /// the cbindgen C FFI library. `"multiplatform"` emits KMP scaffolding.
642    #[serde(default)]
643    pub target: KotlinTarget,
644    /// Emission mode controlling which Kotlin project layout is generated.
645    ///
646    /// Accepted values:
647    /// - `"jvm"` (default) — standard JVM-only project under `packages/kotlin/`
648    /// - `"kmp"` — Kotlin Multiplatform project under `packages/kotlin-mpp/`
649    /// - `"android"` — Android library project under `packages/kotlin-android/`
650    ///
651    /// When `None`, defaults to `"jvm"`.
652    #[serde(default)]
653    pub mode: Option<String>,
654    /// FFI strategy. `"panama"` (default) consumes the Java/Panama FFM facade.
655    /// `"jni"` emits a Kotlin Bridge object with `external fun` declarations
656    /// and a `DefaultClient` class holding a `Long` handle. Android backend
657    /// forces `"jni"` regardless of this setting.
658    #[serde(default)]
659    pub ffi_style: KotlinFfiStyle,
660}
661
662/// Configuration for the dedicated Kotlin/Android backend (`alef-backend-kotlin-android`).
663///
664/// Distinct from [`KotlinConfig`] (Kotlin/JVM). When a crate targets the
665/// `kotlin_android` language slug, this struct controls the emitted
666/// `build.gradle.kts`, `AndroidManifest.xml`, namespace, Maven publish
667/// coordinates, ABI list, and the bundled Java facade emitted into
668/// `src/main/java/` so the AAR is self-contained.
669#[derive(Debug, Clone, Default, Serialize, Deserialize)]
670pub struct KotlinAndroidConfig {
671    /// JVM-style package for Kotlin bindings (e.g. `dev.kreuzberg`).
672    /// Defaults to the crate name.
673    #[serde(default)]
674    pub package: Option<String>,
675    /// Android library manifest `namespace`. Defaults to `package`.
676    #[serde(default)]
677    pub namespace: Option<String>,
678    /// Maven `artifactId` for the generated AAR. Defaults to `{crate}-android`.
679    #[serde(default)]
680    pub artifact_id: Option<String>,
681    /// Maven `groupId` for the generated AAR. No default — when unset the
682    /// emitter falls back to `package`.
683    #[serde(default)]
684    pub group_id: Option<String>,
685    /// Android compile SDK level. Defaults to `template_versions::toolchain::ANDROID_COMPILE_SDK`.
686    #[serde(default)]
687    pub compile_sdk: Option<u32>,
688    /// Android min SDK level. Defaults to `template_versions::toolchain::ANDROID_MIN_SDK`.
689    #[serde(default)]
690    pub min_sdk: Option<u32>,
691    /// JVM bytecode target for Kotlin and Java compilation
692    /// (e.g. `"17"`). Defaults to `template_versions::toolchain::ANDROID_JVM_TARGET`.
693    #[serde(default)]
694    pub jvm_target: Option<String>,
695    /// ABIs to scaffold under `src/main/jniLibs/<abi>/`. Defaults to
696    /// `["arm64-v8a", "x86_64"]`.
697    #[serde(default)]
698    pub abis: Option<Vec<String>>,
699    /// Override the serde rename_all strategy for JSON field names.
700    #[serde(default)]
701    pub serde_rename_all: Option<String>,
702    /// Per-field name remapping for this language. Key is `TypeName.field_name`.
703    #[serde(default)]
704    pub rename_fields: HashMap<String, String>,
705    /// Functions to exclude from generation.
706    #[serde(default)]
707    pub exclude_functions: Vec<String>,
708    /// Types to exclude from generation.
709    #[serde(default)]
710    pub exclude_types: Vec<String>,
711    /// Prefix wrapper for default tool invocations.
712    #[serde(default)]
713    pub run_wrapper: Option<String>,
714    /// Extra paths to append to default lint commands.
715    #[serde(default)]
716    pub extra_lint_paths: Vec<String>,
717    /// Per-language feature override. When set, these features are used instead of
718    /// `[crate] features` for this language's binding crate.
719    #[serde(default)]
720    pub features: Option<Vec<String>>,
721}
722
723/// Configuration for the JNI Rust shim crate emitter (`alef-backend-jni`).
724///
725/// No crate-specific fields are required — all identifiers are derived from
726/// the paired `[crates.kotlin_android]` section (package, features, etc.).
727/// This config struct exists so the crate can target `jni` in `languages`
728/// without needing to configure anything extra.
729#[derive(Debug, Clone, Default, Serialize, Deserialize)]
730pub struct JniConfig {}
731
732/// Dart bridging style: FRB (default) or raw `dart:ffi`.
733#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
734#[serde(rename_all = "lowercase")]
735pub enum DartStyle {
736    /// flutter_rust_bridge — emits a Rust crate plus Dart wrappers using
737    /// FRB-generated bridge symbols. Default.
738    #[default]
739    Frb,
740    /// Raw `dart:ffi` over the cbindgen C ABI — emits Dart-only source that
741    /// loads the shared library at runtime. Cheaper to ship; loses FRB's
742    /// async ergonomics and freezed-style data classes.
743    Ffi,
744}
745
746#[derive(Debug, Clone, Serialize, Deserialize)]
747pub struct GleamConfig {
748    pub app_name: Option<String>,
749    /// Erlang atom name for @external(erlang, "<nif>", ...) lookups (e.g., "my_app_nif").
750    /// Defaults to the app_name.
751    #[serde(default)]
752    pub nif_module: Option<String>,
753    #[serde(default)]
754    pub features: Option<Vec<String>>,
755    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
756    /// When set, this takes priority over the IR type-level serde_rename_all.
757    #[serde(default)]
758    pub serde_rename_all: Option<String>,
759    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
760    /// desired binding field name. Applied after automatic keyword escaping.
761    #[serde(default)]
762    pub rename_fields: HashMap<String, String>,
763    /// Functions to exclude from Gleam binding generation.
764    #[serde(default)]
765    pub exclude_functions: Vec<String>,
766    /// Types to exclude from Gleam binding generation.
767    #[serde(default)]
768    pub exclude_types: Vec<String>,
769    /// Prefix wrapper for default tool invocations.
770    #[serde(default)]
771    pub run_wrapper: Option<String>,
772    /// Extra paths to append to default lint commands.
773    #[serde(default)]
774    pub extra_lint_paths: Vec<String>,
775    /// Per-`element_type` Gleam record-constructor recipes used by the e2e
776    /// generator when emitting `json_object` arg literals. Each entry maps a
777    /// fixture-side `element_type` string (e.g. `"BatchFileItem"`) to a
778    /// structured constructor description that the codegen interpolates per
779    /// JSON-array item. Without an entry the codegen falls back to the
780    /// `json_object_wrapper` (or a plain `json_to_gleam`).
781    ///
782    /// Example:
783    ///
784    /// ```toml
785    /// [[crates.gleam.element_constructors]]
786    /// element_type = "BatchFileItem"
787    /// constructor = "kreuzberg.BatchFileItem"
788    /// [[crates.gleam.element_constructors.fields]]
789    /// gleam_field = "path"
790    /// kind = "file_path"
791    /// json_field = "path"
792    /// [[crates.gleam.element_constructors.fields]]
793    /// gleam_field = "config"
794    /// kind = "literal"
795    /// value = "option.None"
796    /// ```
797    #[serde(default)]
798    pub element_constructors: Vec<GleamElementConstructor>,
799    /// Optional Gleam expression template used to wrap `json_object` arg
800    /// values when no `element_type` recipe matches. The placeholder
801    /// `{json}` is replaced with a Gleam string literal containing the JSON
802    /// form of the arg value, allowing the downstream's Gleam binding to do
803    /// its own parsing.
804    ///
805    /// Example:
806    ///
807    /// ```toml
808    /// [crates.gleam]
809    /// json_object_wrapper = "kreuzberg.config_from_json_string({json})"
810    /// ```
811    ///
812    /// When `None`, the codegen emits `{json}` verbatim (a plain Gleam
813    /// string), matching the iter15 default.
814    #[serde(default)]
815    pub json_object_wrapper: Option<String>,
816}
817
818/// One per-`element_type` Gleam record-constructor recipe. Keyed by the
819/// fixture-side `element_type` string and consumed by the e2e Gleam codegen
820/// when building `json_object` arg literals.
821#[derive(Debug, Clone, Serialize, Deserialize)]
822pub struct GleamElementConstructor {
823    /// Fixture-side `element_type` value this recipe applies to (e.g.
824    /// `"BatchFileItem"`).
825    pub element_type: String,
826    /// Fully-qualified Gleam constructor identifier (e.g.
827    /// `"kreuzberg.BatchFileItem"`). Emitted verbatim before the `(...)` field
828    /// list.
829    pub constructor: String,
830    /// Ordered list of fields to emit inside the constructor's `(...)` block,
831    /// in argument-position order. Each field describes how its value is
832    /// derived from the per-item JSON object.
833    pub fields: Vec<GleamElementField>,
834}
835
836/// One field inside a [`GleamElementConstructor`]'s argument list.
837///
838/// `kind` selects the source/encoding strategy:
839/// * `"file_path"` — read `json_field` from the JSON object as a string,
840///   prefix with the configured `test_documents_dir` when the value does not
841///   start with `/`, and emit as a Gleam string literal.
842/// * `"byte_array"` — read `json_field` from the JSON object as a JSON
843///   `Array(Number)` and emit as a Gleam BitArray literal `<<n1, n2, …>>`.
844/// * `"string"` — read `json_field` as a string, emit as a Gleam string
845///   literal; falls back to `default` (or empty) if missing.
846/// * `"literal"` — emit `value` verbatim (no JSON lookup). Use for
847///   constant fields like `config: option.None`.
848#[derive(Debug, Clone, Serialize, Deserialize)]
849pub struct GleamElementField {
850    /// Gleam record field name (e.g. `"path"`, `"config"`).
851    pub gleam_field: String,
852    /// Source/encoding strategy. See struct doc.
853    pub kind: String,
854    /// JSON object key to read, when `kind` is one of the JSON-driven
855    /// strategies. Required for `"file_path"`, `"byte_array"`, `"string"`;
856    /// ignored for `"literal"`.
857    #[serde(default)]
858    pub json_field: Option<String>,
859    /// Default Gleam expression when `json_field` is missing/null. Only
860    /// honoured by the `"string"` strategy today.
861    #[serde(default)]
862    pub default: Option<String>,
863    /// Verbatim Gleam expression to emit when `kind = "literal"`.
864    #[serde(default)]
865    pub value: Option<String>,
866}
867
868#[derive(Debug, Clone, Default, Serialize, Deserialize)]
869pub struct DartConfig {
870    /// Dart pub.dev package name (e.g. `"my_package"`). Used as the `name` in
871    /// `pubspec.yaml`. Defaults to a snake_case derivation of the crate name.
872    #[serde(default)]
873    pub pubspec_name: Option<String>,
874    /// Dart library name (the `library` declaration). Defaults to the pubspec name.
875    #[serde(default)]
876    pub lib_name: Option<String>,
877    /// Dart package name override (e.g. for pub.dev scoped packages).
878    #[serde(default)]
879    pub package_name: Option<String>,
880    /// Bridging style. `"frb"` (default) uses flutter_rust_bridge; `"ffi"` emits
881    /// raw `dart:ffi` source over the cbindgen C library.
882    #[serde(default)]
883    pub style: DartStyle,
884    /// flutter_rust_bridge version to pin in generated pubspec.yaml.
885    /// Defaults to `template_versions::cargo::FLUTTER_RUST_BRIDGE` when unset.
886    #[serde(default)]
887    pub frb_version: Option<String>,
888    /// Cargo features to enable on the binding crate.
889    #[serde(default)]
890    pub features: Option<Vec<String>>,
891    /// Additional Cargo dependencies for the generated Dart Rust bridge crate.
892    #[serde(default)]
893    pub extra_dependencies: HashMap<String, toml::Value>,
894    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
895    #[serde(default)]
896    pub serde_rename_all: Option<String>,
897    /// Per-field name remapping. Key is `TypeName.field_name`, value is the
898    /// desired binding field name. Applied after automatic keyword escaping.
899    #[serde(default)]
900    pub rename_fields: HashMap<String, String>,
901    /// Functions to exclude from Dart binding generation.
902    #[serde(default)]
903    pub exclude_functions: Vec<String>,
904    /// Types to exclude from Dart binding generation.
905    #[serde(default)]
906    pub exclude_types: Vec<String>,
907    /// Prefix wrapper for default tool invocations.
908    #[serde(default)]
909    pub run_wrapper: Option<String>,
910    /// Extra paths to append to default lint commands.
911    #[serde(default)]
912    pub extra_lint_paths: Vec<String>,
913    /// Override the core Cargo dependency name and path for the Dart binding crate.
914    /// When set, the binding `Cargo.toml` depends on this crate (resolved as
915    /// `../../../crates/<override>`) instead of the umbrella `[crate.name]`.
916    /// Defaults to unset.
917    #[serde(default)]
918    pub core_crate_override: Option<String>,
919    /// Keys to subtract from the merged `extra_dependencies` set for this
920    /// language only.
921    #[serde(default)]
922    pub exclude_extra_dependencies: Vec<String>,
923    /// Method names whose Rust bridge body should be emitted as `unimplemented!()`.
924    ///
925    /// Use this when a function's FFI signature (e.g. nested tuples containing
926    /// `Vec<u8>`) cannot be represented across the FRB bridge at all. Consumers must
927    /// list the method names explicitly — this field has no built-in defaults so the
928    /// knob is library-agnostic.
929    ///
930    /// Example (`alef.toml`):
931    /// ```toml
932    /// [crates.dart]
933    /// stub_methods = ["batch_extract_bytes", "batch_extract_bytes_sync"]
934    /// ```
935    #[serde(default)]
936    pub stub_methods: Vec<String>,
937    /// Per-target Cargo dependency overrides for the binding crate.
938    ///
939    /// When set, the emitted `Cargo.toml` wraps the base core dependency in a
940    /// `[target.'cfg(not(<cfg>))'.dependencies]` section and adds a matching
941    /// `[target.'cfg(<cfg>)'.dependencies]` block using `override_features`
942    /// (and `default_features = false` when `override_default_features = false`).
943    /// Required when the binding has to swap the feature set on a specific
944    /// target triple, e.g. Android x86_64 dropping ORT-dependent features.
945    ///
946    /// Example (`alef.toml`):
947    /// ```toml
948    /// [[crates.dart.target_dep_overrides]]
949    /// cfg = "all(target_os = \"android\", target_arch = \"x86_64\")"
950    /// features = ["android-target"]
951    /// default_features = false
952    /// ```
953    #[serde(default)]
954    pub target_dep_overrides: Vec<DartTargetDepOverride>,
955}
956
957#[derive(Debug, Clone, Serialize, Deserialize)]
958pub struct DartTargetDepOverride {
959    /// Cargo `cfg(...)` predicate (without the `cfg(...)` wrapper). Example:
960    /// `all(target_os = "android", target_arch = "x86_64")`.
961    pub cfg: String,
962    /// Features to enable on the core dependency for this target.
963    #[serde(default)]
964    pub features: Vec<String>,
965    /// When false (default), emit `default-features = false` for this target.
966    /// When true, allow the core dep's default features through.
967    #[serde(default)]
968    pub default_features: bool,
969}
970
971#[derive(Debug, Clone, Default, Serialize, Deserialize)]
972pub struct SwiftConfig {
973    /// Swift module name (e.g. `"MyLibrary"`). Defaults to PascalCase of the crate name.
974    #[serde(default)]
975    pub module_name: Option<String>,
976    /// Swift package name. Defaults to the module name.
977    #[serde(default)]
978    pub package_name: Option<String>,
979    /// swift-bridge version. Defaults to `template_versions::cargo::SWIFT_BRIDGE` when unset.
980    #[serde(default)]
981    pub swift_bridge_version: Option<String>,
982    /// Minimum macOS deployment target. Defaults to `template_versions::toolchain::SWIFT_MIN_MACOS` when unset.
983    #[serde(default)]
984    pub min_macos_version: Option<String>,
985    /// Minimum iOS deployment target. Defaults to `template_versions::toolchain::SWIFT_MIN_IOS` when unset.
986    #[serde(default)]
987    pub min_ios_version: Option<String>,
988    /// Cargo features to enable on the binding crate.
989    #[serde(default)]
990    pub features: Option<Vec<String>>,
991    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
992    #[serde(default)]
993    pub serde_rename_all: Option<String>,
994    /// Per-field name remapping. Key is `TypeName.field_name`, value is the
995    /// desired binding field name. Applied after automatic keyword escaping.
996    #[serde(default)]
997    pub rename_fields: HashMap<String, String>,
998    /// Functions to exclude from Swift binding generation.
999    #[serde(default)]
1000    pub exclude_functions: Vec<String>,
1001    /// Types to exclude from Swift binding generation.
1002    #[serde(default)]
1003    pub exclude_types: Vec<String>,
1004    /// Fields to exclude from Swift binding generation.
1005    /// Format: `"TypeName.field_name"`.
1006    #[serde(default)]
1007    pub exclude_fields: Vec<String>,
1008    /// Prefix wrapper for default tool invocations.
1009    #[serde(default)]
1010    pub run_wrapper: Option<String>,
1011    /// Extra paths to append to default lint commands.
1012    #[serde(default)]
1013    pub extra_lint_paths: Vec<String>,
1014    /// Override the core Cargo dependency name and path for the Swift binding crate.
1015    /// When set, the binding `Cargo.toml` depends on this crate (resolved as
1016    /// `../../../crates/<override>`) instead of the umbrella `[crate.name]`.
1017    /// Defaults to unset.
1018    #[serde(default)]
1019    pub core_crate_override: Option<String>,
1020    /// Extra Cargo dependencies merged into the generated Swift Rust bridge crate.
1021    #[serde(default)]
1022    pub extra_dependencies: HashMap<String, toml::Value>,
1023    /// Keys to subtract from the merged `extra_dependencies` set for this
1024    /// language only.
1025    #[serde(default)]
1026    pub exclude_extra_dependencies: Vec<String>,
1027    /// Override the auto-generated `create_<type>(api_key, base_url)` constructor
1028    /// body for opaque client types that expose methods. When set, the swift backend
1029    /// emits this snippet verbatim as the function body (no implicit `Ok(...)`).
1030    ///
1031    /// Use this when the source crate's constructor signature differs from the
1032    /// default `Type::new(api_key, base_url)` shape — e.g. liter-llm uses
1033    /// `DefaultClient::new(ClientConfig, Option<&str>)` and needs to build a
1034    /// `ClientConfig` from the bridge inputs first.
1035    ///
1036    /// The snippet is parameterised by `{type_name}` (the wrapper newtype name)
1037    /// and runs in a function body with `api_key: String` and `base_url: Option<String>`
1038    /// already in scope. It must return `Result<{type_name}, String>`.
1039    #[serde(default)]
1040    pub client_constructor_body: HashMap<String, String>,
1041}
1042
1043#[derive(Debug, Clone, Serialize, Deserialize)]
1044pub struct ZigConfig {
1045    pub module_name: Option<String>,
1046    #[serde(default)]
1047    pub features: Option<Vec<String>>,
1048    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
1049    /// When set, this takes priority over the IR type-level serde_rename_all.
1050    #[serde(default)]
1051    pub serde_rename_all: Option<String>,
1052    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
1053    /// desired binding field name. Applied after automatic keyword escaping.
1054    #[serde(default)]
1055    pub rename_fields: HashMap<String, String>,
1056    /// Functions to exclude from Zig binding generation.
1057    #[serde(default)]
1058    pub exclude_functions: Vec<String>,
1059    /// Types to exclude from Zig binding generation.
1060    #[serde(default)]
1061    pub exclude_types: Vec<String>,
1062    /// Prefix wrapper for default tool invocations.
1063    #[serde(default)]
1064    pub run_wrapper: Option<String>,
1065    /// Extra paths to append to default lint commands.
1066    #[serde(default)]
1067    pub extra_lint_paths: Vec<String>,
1068}
1069
1070#[derive(Debug, Clone, Serialize, Deserialize)]
1071pub struct CSharpConfig {
1072    pub namespace: Option<String>,
1073    /// NuGet `<PackageId>` to publish under. When unset, falls back to `namespace`.
1074    /// Use this when the published artifact id must differ from the C# `RootNamespace` —
1075    /// e.g. when the unprefixed name is owned by a third party on nuget.org and
1076    /// you publish under a vendor-prefixed id like `KreuzbergDev.<Lib>`.
1077    #[serde(default)]
1078    pub package_id: Option<String>,
1079    pub target_framework: Option<String>,
1080    #[serde(default)]
1081    pub features: Option<Vec<String>>,
1082    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
1083    /// When set, this takes priority over the IR type-level serde_rename_all.
1084    #[serde(default)]
1085    pub serde_rename_all: Option<String>,
1086    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
1087    /// desired binding field name. Applied after automatic keyword escaping.
1088    #[serde(default)]
1089    pub rename_fields: HashMap<String, String>,
1090    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
1091    /// commands across all pipelines (lint, test, build, etc.).
1092    #[serde(default)]
1093    pub run_wrapper: Option<String>,
1094    /// Extra paths to append to default lint commands (format, check, typecheck).
1095    /// Ignored when project_file is set.
1096    #[serde(default)]
1097    pub extra_lint_paths: Vec<String>,
1098    /// Project file for C# (e.g., "MyProject.csproj", "MySolution.sln"). When set, default
1099    /// lint/build/test commands target this file instead of the output directory.
1100    #[serde(default)]
1101    pub project_file: Option<String>,
1102    /// Types to exclude from C# binding generation.
1103    ///
1104    /// C# bindings call the generated C FFI through P/Invoke, so types excluded from
1105    /// `[crates.ffi].exclude_types` are also excluded automatically by the C# backend.
1106    #[serde(default)]
1107    pub exclude_types: Vec<String>,
1108    /// Functions to exclude from C# binding generation (e.g., functions not present in the
1109    /// C FFI layer). Excluded functions are omitted from both NativeMethods.cs and the
1110    /// wrapper class.
1111    #[serde(default)]
1112    pub exclude_functions: Vec<String>,
1113}
1114
1115#[derive(Debug, Clone, Serialize, Deserialize)]
1116pub struct RConfig {
1117    pub package_name: Option<String>,
1118    #[serde(default)]
1119    pub features: Option<Vec<String>>,
1120    /// Override the serde rename_all strategy for JSON field names (e.g. "camelCase", "snake_case").
1121    /// When set, this takes priority over the IR type-level serde_rename_all.
1122    #[serde(default)]
1123    pub serde_rename_all: Option<String>,
1124    /// Per-field name remapping for this language. Key is `TypeName.field_name`, value is the
1125    /// desired binding field name. Applied after automatic keyword escaping.
1126    #[serde(default)]
1127    pub rename_fields: HashMap<String, String>,
1128    /// Prefix wrapper for default tool invocations. When set, prepends this string to default
1129    /// commands across all pipelines (lint, test, build, etc.).
1130    #[serde(default)]
1131    pub run_wrapper: Option<String>,
1132    /// Extra paths to append to default lint commands (format, check, typecheck).
1133    #[serde(default)]
1134    pub extra_lint_paths: Vec<String>,
1135}
1136
1137/// Custom modules that alef should declare (mod X;) but not generate.
1138/// These are hand-written modules imported by the generated lib.rs.
1139#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1140pub struct CustomModulesConfig {
1141    #[serde(default)]
1142    pub python: Vec<String>,
1143    #[serde(default)]
1144    pub node: Vec<String>,
1145    #[serde(default)]
1146    pub ruby: Vec<String>,
1147    #[serde(default)]
1148    pub php: Vec<String>,
1149    #[serde(default)]
1150    pub elixir: Vec<String>,
1151    #[serde(default)]
1152    pub wasm: Vec<String>,
1153    #[serde(default)]
1154    pub ffi: Vec<String>,
1155    #[serde(default)]
1156    pub go: Vec<String>,
1157    #[serde(default)]
1158    pub java: Vec<String>,
1159    #[serde(default)]
1160    pub csharp: Vec<String>,
1161    #[serde(default)]
1162    pub r: Vec<String>,
1163}
1164
1165impl CustomModulesConfig {
1166    pub fn for_language(&self, lang: Language) -> &[String] {
1167        match lang {
1168            Language::Python => &self.python,
1169            Language::Node => &self.node,
1170            Language::Ruby => &self.ruby,
1171            Language::Php => &self.php,
1172            Language::Elixir => &self.elixir,
1173            Language::Wasm => &self.wasm,
1174            Language::Ffi => &self.ffi,
1175            Language::Go => &self.go,
1176            Language::Java => &self.java,
1177            Language::Csharp => &self.csharp,
1178            Language::R => &self.r,
1179            Language::Rust => &[], // Rust doesn't need custom modules (no binding crate)
1180            Language::Kotlin
1181            | Language::KotlinAndroid
1182            | Language::Swift
1183            | Language::Dart
1184            | Language::Gleam
1185            | Language::Zig
1186            | Language::Jni
1187            | Language::C => &[],
1188        }
1189    }
1190}
1191
1192/// Custom classes/functions from hand-written modules to register in module init.
1193#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1194pub struct CustomRegistration {
1195    #[serde(default)]
1196    pub classes: Vec<String>,
1197    #[serde(default)]
1198    pub functions: Vec<String>,
1199    #[serde(default)]
1200    pub init_calls: Vec<String>,
1201}
1202
1203/// Per-language custom registrations.
1204#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1205pub struct CustomRegistrationsConfig {
1206    #[serde(default)]
1207    pub python: Option<CustomRegistration>,
1208    #[serde(default)]
1209    pub node: Option<CustomRegistration>,
1210    #[serde(default)]
1211    pub ruby: Option<CustomRegistration>,
1212    #[serde(default)]
1213    pub php: Option<CustomRegistration>,
1214    #[serde(default)]
1215    pub elixir: Option<CustomRegistration>,
1216    #[serde(default)]
1217    pub wasm: Option<CustomRegistration>,
1218}
1219
1220impl CustomRegistrationsConfig {
1221    pub fn for_language(&self, lang: Language) -> Option<&CustomRegistration> {
1222        match lang {
1223            Language::Python => self.python.as_ref(),
1224            Language::Node => self.node.as_ref(),
1225            Language::Ruby => self.ruby.as_ref(),
1226            Language::Php => self.php.as_ref(),
1227            Language::Elixir => self.elixir.as_ref(),
1228            Language::Wasm => self.wasm.as_ref(),
1229            _ => None,
1230        }
1231    }
1232}