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}