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