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