Skip to main content

ryo_app/spec/
response.rs

1//! SpecFlow response types for API/CLI consumption.
2
3use serde::{Deserialize, Serialize};
4
5/// SpecFlow query result.
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct SpecShowResponse {
8    /// All groups with their specs.
9    pub groups: Vec<SpecGroupInfo>,
10    /// All dependency relations.
11    pub relations: Vec<SpecRelation>,
12    /// Statistics.
13    pub stats: SpecStats,
14}
15
16/// Information about a spec group.
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct SpecGroupInfo {
19    /// Group name.
20    pub name: String,
21    /// Specs in this group.
22    pub specs: Vec<SpecInfo>,
23}
24
25/// Information about a single spec alias.
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct SpecInfo {
28    /// Alias name (e.g., "DbConfig").
29    pub alias_name: String,
30    /// Wrapped type name (e.g., "DatabaseConfig").
31    pub wrapped_type_name: String,
32    /// Source of this spec.
33    pub source: SpecSourceKind,
34}
35
36/// Source of spec information.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(rename_all = "snake_case")]
39pub enum SpecSourceKind {
40    /// From `type X = Spec<G, T>` (strict, compile-time).
41    TypeAlias,
42    /// From `@spec:group(G)` comment (flexible, advisory).
43    Comment,
44    /// Inferred by analysis.
45    Inferred,
46}
47
48/// Dependency relation between specs.
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct SpecRelation {
51    /// Source spec name.
52    pub from: String,
53    /// Target spec name.
54    pub to: String,
55    /// Relation kind.
56    pub kind: SpecRelationKind,
57}
58
59/// Kind of spec relation.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(rename_all = "snake_case")]
62pub enum SpecRelationKind {
63    /// Dependency relation.
64    DependsOn,
65    /// Related types.
66    RelatedTo,
67}
68
69/// SpecFlow statistics.
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct SpecStats {
72    /// Number of groups.
73    pub groups: usize,
74    /// Number of specs.
75    pub specs: usize,
76    /// Total node count.
77    pub nodes: usize,
78    /// Total edge count.
79    pub edges: usize,
80}
81
82/// Lint issue found in specs.
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct SpecLintIssue {
85    /// Issue severity.
86    pub severity: LintSeverity,
87    /// Issue message.
88    pub message: String,
89    /// Optional location.
90    pub location: Option<String>,
91}
92
93/// Lint issue severity.
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
95#[serde(rename_all = "snake_case")]
96pub enum LintSeverity {
97    /// Warning level.
98    Warning,
99    /// Error level.
100    Error,
101}
102
103/// Lint result.
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct SpecLintResult {
106    /// All issues found.
107    pub issues: Vec<SpecLintIssue>,
108    /// Number of warnings.
109    pub warnings: usize,
110    /// Number of errors.
111    pub errors: usize,
112}
113
114impl SpecLintResult {
115    /// Check if there are any errors.
116    pub fn has_errors(&self) -> bool {
117        self.errors > 0
118    }
119
120    /// Check if there are any issues.
121    pub fn has_issues(&self) -> bool {
122        !self.issues.is_empty()
123    }
124}