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