use indexmap::IndexMap;
use super::mcp::RawMcpConfig;
use super::task::RawTask;
use crate::source::{Span, Spanned};
#[derive(Debug, Clone, Default)]
pub struct RawWorkflow {
pub schema: Spanned<String>,
pub workflow: Option<Spanned<String>>,
pub description: Option<Spanned<String>>,
pub provider: Option<Spanned<String>>,
pub model: Option<Spanned<String>>,
pub mcp: Option<Spanned<RawMcpConfig>>,
pub pkg: Option<Spanned<RawPkgConfig>>,
pub context: Option<Spanned<RawContextConfig>>,
pub imports: Option<Spanned<Vec<Spanned<RawImportSpec>>>>,
pub inputs: Option<Spanned<IndexMap<Spanned<String>, Spanned<serde_json::Value>>>>,
pub artifacts: Option<Spanned<serde_json::Value>>,
pub log: Option<Spanned<serde_json::Value>>,
pub agents: Option<Spanned<serde_json::Value>>,
pub tasks: Spanned<Vec<Spanned<RawTask>>>,
pub span: Span,
}
#[derive(Debug, Clone, Default)]
pub struct RawPkgConfig {
pub include: Vec<Spanned<String>>,
}
#[derive(Debug, Clone, Default)]
pub struct RawContextConfig {
pub files: Option<IndexMap<Spanned<String>, Spanned<String>>>,
}
#[derive(Debug, Clone, Default)]
pub struct RawImportSpec {
pub path: Spanned<String>,
pub prefix: Option<Spanned<String>>,
pub span: Span,
}
impl RawWorkflow {
pub fn new() -> Self {
Self::default()
}
pub fn name(&self) -> &str {
self.workflow
.as_ref()
.map(|s| s.value.as_str())
.unwrap_or("unnamed")
}
pub fn task_count(&self) -> usize {
self.tasks.value.len()
}
pub fn iter_tasks(&self) -> impl Iterator<Item = &Spanned<RawTask>> {
self.tasks.value.iter()
}
pub fn get_task(&self, id: &str) -> Option<&Spanned<RawTask>> {
self.tasks.value.iter().find(|t| t.value.id.value == id)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::source::{FileId, Span};
fn make_span(start: u32, end: u32) -> Span {
Span::new(FileId(0), start, end)
}
#[test]
fn test_raw_workflow_default() {
let workflow = RawWorkflow::default();
assert_eq!(workflow.task_count(), 0);
assert_eq!(workflow.name(), "unnamed");
}
#[test]
fn test_raw_workflow_with_tasks() {
use super::super::task::RawTask;
let mut workflow = RawWorkflow::new();
workflow.workflow = Some(Spanned::new("test-workflow".to_string(), make_span(0, 13)));
workflow.tasks = Spanned::new(
vec![
Spanned::new(
RawTask {
id: Spanned::new("task1".to_string(), make_span(20, 25)),
..Default::default()
},
make_span(18, 50),
),
Spanned::new(
RawTask {
id: Spanned::new("task2".to_string(), make_span(60, 65)),
..Default::default()
},
make_span(58, 90),
),
],
make_span(15, 95),
);
assert_eq!(workflow.task_count(), 2);
assert_eq!(workflow.name(), "test-workflow");
assert!(workflow.get_task("task1").is_some());
assert!(workflow.get_task("task2").is_some());
assert!(workflow.get_task("task3").is_none());
}
#[test]
fn test_raw_import_spec() {
let import = RawImportSpec {
path: Spanned::new("./partials/setup.nika.yaml".to_string(), make_span(0, 25)),
prefix: Some(Spanned::new("setup_".to_string(), make_span(30, 36))),
span: make_span(0, 40),
};
assert_eq!(import.path.value, "./partials/setup.nika.yaml");
assert_eq!(import.prefix.as_ref().unwrap().value, "setup_");
}
}