diff --git a/lib/components/fabro-workflow/src/transforms/variable_expansion.rs b/lib/components/fabro-workflow/src/transforms/variable_expansion.rs index da7aba76d..eb33f250f 100644 --- a/lib/components/fabro-workflow/src/transforms/variable_expansion.rs +++ b/lib/components/fabro-workflow/src/transforms/variable_expansion.rs @@ -519,7 +519,7 @@ impl TemplateTransform { continue; } if let Some(kind) = reference_kind_for_attribute(scope, attr_name, text) { - validate_static_reference(text, kind) + validate_static_reference(text, kind.into()) .map_err(|error| Error::Validation(error.to_string()))?; continue; } diff --git a/lib/foundation/fabro-template/src/static_reference.rs b/lib/foundation/fabro-template/src/static_reference.rs index b832f2956..e2678ea65 100644 --- a/lib/foundation/fabro-template/src/static_reference.rs +++ b/lib/foundation/fabro-template/src/static_reference.rs @@ -11,7 +11,9 @@ //! reference-bearing attribute is added here once instead of drifting between //! per-crate walkers. -use fabro_types::graph::{AttributeScope, Graph, ReferenceKind, reference_kind_for_attribute}; +use fabro_types::graph::{ + AttributeScope, Graph, GraphReferenceKind, ReferenceKind, reference_kind_for_attribute, +}; use crate::contains_template_syntax; @@ -119,20 +121,19 @@ pub fn visit_graph_references<'graph, E>( continue; }; let reference = match kind { - ReferenceKind::Import | ReferenceKind::ChildWorkflow => value, - // Classification only yields FileInline for `@` values. - ReferenceKind::FileInline => value + GraphReferenceKind::Import | GraphReferenceKind::ChildWorkflow => value, + // Classification only yields these kinds for `@` values. + GraphReferenceKind::FileInline | GraphReferenceKind::GraphGoalFile => value .strip_prefix('@') - .expect("file inline classification requires a leading '@'"), - ReferenceKind::Dockerfile | ReferenceKind::GraphGoalFile => continue, + .expect("file reference classification requires a leading '@'"), }; - validate_static_reference(reference, kind) + validate_static_reference(reference, kind.into()) .map_err(GraphReferenceError::StaticReference)?; let event = match kind { - ReferenceKind::Import => GraphReference::Import { reference }, - ReferenceKind::ChildWorkflow => GraphReference::ChildWorkflow { reference }, - ReferenceKind::FileInline => GraphReference::FileInline { key, reference }, - ReferenceKind::Dockerfile | ReferenceKind::GraphGoalFile => unreachable!(), + GraphReferenceKind::Import => GraphReference::Import { reference }, + GraphReferenceKind::ChildWorkflow => GraphReference::ChildWorkflow { reference }, + GraphReferenceKind::FileInline => GraphReference::FileInline { key, reference }, + GraphReferenceKind::GraphGoalFile => GraphReference::GoalFile { reference }, }; visit(event).map_err(GraphReferenceError::Visit)?; } diff --git a/lib/foundation/fabro-types/src/graph.rs b/lib/foundation/fabro-types/src/graph.rs index b9f74b79f..e0d7dc17c 100644 --- a/lib/foundation/fabro-types/src/graph.rs +++ b/lib/foundation/fabro-types/src/graph.rs @@ -598,8 +598,7 @@ pub enum AttributeScope { Edge, } -/// Kinds of static (non-templated) file references a graph attribute can -/// carry. +/// Kinds of static (non-templated) workflow-owned file references. #[derive(Clone, Copy, Debug, Eq, PartialEq, strum::Display)] pub enum ReferenceKind { #[strum(to_string = "file inline reference")] @@ -614,25 +613,48 @@ pub enum ReferenceKind { GraphGoalFile, } +/// Kinds of static file references that graph attributes can carry: the +/// subset of [`ReferenceKind`] that [`reference_kind_for_attribute`] can +/// classify. Config-sourced kinds (Dockerfiles) are unrepresentable here by +/// construction. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum GraphReferenceKind { + FileInline, + Import, + ChildWorkflow, + GraphGoalFile, +} + +impl From for ReferenceKind { + fn from(kind: GraphReferenceKind) -> Self { + match kind { + GraphReferenceKind::FileInline => Self::FileInline, + GraphReferenceKind::Import => Self::Import, + GraphReferenceKind::ChildWorkflow => Self::ChildWorkflow, + GraphReferenceKind::GraphGoalFile => Self::GraphGoalFile, + } + } +} + /// Classify a graph attribute as a static file reference, if it is one. #[must_use] pub fn reference_kind_for_attribute( scope: AttributeScope, key: &str, value: &str, -) -> Option { +) -> Option { match key { - "import" if matches!(scope, AttributeScope::Node) => Some(ReferenceKind::Import), + "import" if matches!(scope, AttributeScope::Node) => Some(GraphReferenceKind::Import), "stack.child_workflow" if matches!(scope, AttributeScope::Node) => { - Some(ReferenceKind::ChildWorkflow) + Some(GraphReferenceKind::ChildWorkflow) } "goal" if matches!(scope, AttributeScope::Graph) && value.starts_with('@') => { - Some(ReferenceKind::GraphGoalFile) + Some(GraphReferenceKind::GraphGoalFile) } "prompt" | "output_schema" if matches!(scope, AttributeScope::Node) && value.starts_with('@') => { - Some(ReferenceKind::FileInline) + Some(GraphReferenceKind::FileInline) } _ => None, } @@ -1168,7 +1190,7 @@ mod tests { "output_schema", "@schemas/result.schema.json", ), - Some(ReferenceKind::FileInline), + Some(GraphReferenceKind::FileInline), ); }