Skip to main content

alef_core/config/
languages.rs

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