Skip to main content

alef_core/config/
e2e.rs

1//! E2E test generation configuration types.
2
3use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, HashSet};
5
6/// Root e2e configuration from `[e2e]` section of alef.toml.
7#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8pub struct E2eConfig {
9    /// Directory containing fixture JSON files (default: "fixtures").
10    #[serde(default = "default_fixtures_dir")]
11    pub fixtures: String,
12    /// Output directory for generated e2e test projects (default: "e2e").
13    #[serde(default = "default_output_dir")]
14    pub output: String,
15    /// Languages to generate e2e tests for. Defaults to top-level `languages` list.
16    #[serde(default)]
17    pub languages: Vec<String>,
18    /// Function call configuration.
19    pub call: CallConfig,
20    /// Per-language package reference overrides.
21    #[serde(default)]
22    pub packages: HashMap<String, PackageRef>,
23    /// Per-language formatter commands.
24    #[serde(default)]
25    pub format: HashMap<String, String>,
26    /// Field path aliases: maps fixture field paths to actual API struct paths.
27    /// E.g., "metadata.title" -> "metadata.document.title"
28    /// Supports struct access (foo.bar), map access (foo[key]), direct fields.
29    #[serde(default)]
30    pub fields: HashMap<String, String>,
31    /// Fields that are Optional/nullable in the return type.
32    /// Rust generators use .as_deref().unwrap_or("") for strings, .is_some() for structs.
33    #[serde(default)]
34    pub fields_optional: HashSet<String>,
35}
36
37fn default_fixtures_dir() -> String {
38    "fixtures".to_string()
39}
40
41fn default_output_dir() -> String {
42    "e2e".to_string()
43}
44
45/// Configuration for the function call in each test.
46#[derive(Debug, Clone, Serialize, Deserialize, Default)]
47pub struct CallConfig {
48    /// The function name (alef applies language naming conventions).
49    #[serde(default)]
50    pub function: String,
51    /// The module/package where the function lives.
52    #[serde(default)]
53    pub module: String,
54    /// Variable name for the return value (default: "result").
55    #[serde(default = "default_result_var")]
56    pub result_var: String,
57    /// Whether the function is async.
58    #[serde(default)]
59    pub r#async: bool,
60    /// How fixture `input` fields map to function arguments.
61    #[serde(default)]
62    pub args: Vec<ArgMapping>,
63    /// Per-language overrides for module/function/etc.
64    #[serde(default)]
65    pub overrides: HashMap<String, CallOverride>,
66}
67
68fn default_result_var() -> String {
69    "result".to_string()
70}
71
72/// Maps a fixture input field to a function argument.
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct ArgMapping {
75    /// Argument name in the function signature.
76    pub name: String,
77    /// JSON field path in the fixture's `input` object.
78    pub field: String,
79    /// Type hint for code generation.
80    #[serde(rename = "type", default = "default_arg_type")]
81    pub arg_type: String,
82    /// Whether this argument is optional.
83    #[serde(default)]
84    pub optional: bool,
85}
86
87fn default_arg_type() -> String {
88    "string".to_string()
89}
90
91/// Per-language override for function call configuration.
92#[derive(Debug, Clone, Serialize, Deserialize, Default)]
93pub struct CallOverride {
94    /// Override the module/import path.
95    #[serde(default)]
96    pub module: Option<String>,
97    /// Override the function name.
98    #[serde(default)]
99    pub function: Option<String>,
100    /// Override the crate name (Rust only).
101    #[serde(default)]
102    pub crate_name: Option<String>,
103    /// Override the class name (Java/C# only).
104    #[serde(default)]
105    pub class: Option<String>,
106    /// Import alias (Go only, e.g., `htmd`).
107    #[serde(default)]
108    pub alias: Option<String>,
109    /// C header file name (C only).
110    #[serde(default)]
111    pub header: Option<String>,
112    /// FFI symbol prefix (C only).
113    #[serde(default)]
114    pub prefix: Option<String>,
115    /// For json_object args: the constructor to use instead of raw dict/object.
116    /// E.g., "ConversionOptions" — generates `ConversionOptions(**options)` in Python,
117    /// `new ConversionOptions(options)` in TypeScript.
118    #[serde(default)]
119    pub options_type: Option<String>,
120    /// How to pass json_object args: "kwargs" (default), "dict", or "json".
121    ///
122    /// - `"kwargs"`: construct `OptionsType(key=val, ...)` (requires `options_type`).
123    /// - `"dict"`: pass as a plain dict/object literal `{"key": "val"}`.
124    /// - `"json"`: pass via `json.loads('...')` / `JSON.parse('...')`.
125    #[serde(default)]
126    pub options_via: Option<String>,
127    /// Maps fixture option field names to their enum type names.
128    /// E.g., `{"headingStyle": "HeadingStyle", "codeBlockStyle": "CodeBlockStyle"}`.
129    /// The generator imports these types and maps string values to enum constants.
130    #[serde(default)]
131    pub enum_fields: HashMap<String, String>,
132    /// Module to import enum types from (if different from the main module).
133    /// E.g., "html_to_markdown._html_to_markdown" for PyO3 native enums.
134    #[serde(default)]
135    pub enum_module: Option<String>,
136}
137
138/// Per-language package reference configuration.
139#[derive(Debug, Clone, Serialize, Deserialize, Default)]
140pub struct PackageRef {
141    /// Package/crate/gem/module name.
142    #[serde(default)]
143    pub name: Option<String>,
144    /// Relative path from e2e/{lang}/ to the package.
145    #[serde(default)]
146    pub path: Option<String>,
147    /// Go module path.
148    #[serde(default)]
149    pub module: Option<String>,
150    /// Package version (e.g., for go.mod require directives).
151    #[serde(default)]
152    pub version: Option<String>,
153}