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