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