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