canon_protocol/
specification.rs

1use serde::{Deserialize, Serialize};
2use serde_yaml::Value;
3use std::collections::HashMap;
4
5/// Canon Protocol Specification
6///
7/// This represents ANY Canon document - whether it's a type definition,
8/// a project specification, or any other kind of Canon specification.
9/// The `type` field determines what kind of specification this is.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct CanonSpecification {
12    /// Protocol version (e.g., "1.0")
13    pub canon: String,
14
15    /// Type reference - determines what kind of specification this is
16    /// Examples:
17    /// - "canon-protocol.org/type@1.0.0" for type definitions
18    /// - "canon-protocol.org/project@1.0.0" for projects
19    /// - "content.org/blog-post@1.0.0" for a blog post
20    pub r#type: String,
21
22    /// Required metadata for all specifications
23    pub metadata: SpecificationMetadata,
24
25    /// Optional includes for type composition (used when this is a type definition)
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub includes: Option<Vec<String>>,
28
29    /// Optional schema definition (only present when this is a type definition)
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub schema: Option<HashMap<String, SchemaField>>,
32
33    /// Type-specific content (any fields defined by the type's schema)
34    #[serde(flatten)]
35    pub content: HashMap<String, Value>,
36}
37
38/// Required metadata for all specifications
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct SpecificationMetadata {
41    /// Unique identifier (lowercase, alphanumeric with hyphens)
42    pub id: String,
43
44    /// Semantic version (MAJOR.MINOR.PATCH)
45    pub version: String,
46
47    /// Publisher domain or subdomain
48    pub publisher: String,
49
50    /// Optional human-readable title
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub title: Option<String>,
53
54    /// Optional description
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub description: Option<String>,
57}
58
59/// Schema field definition
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct SchemaField {
62    /// Field type
63    pub r#type: FieldType,
64
65    /// Whether the field is required
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub required: Option<bool>,
68
69    /// For ref types, the URI with optional version operators
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub uri: Option<String>,
72
73    /// Pattern for string validation
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub pattern: Option<String>,
76
77    /// Enumeration of allowed values
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub r#enum: Option<Vec<Value>>,
80
81    /// For objects, property definitions
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub properties: Option<HashMap<String, SchemaField>>,
84
85    /// For arrays, item schema
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub items: Option<Box<SchemaField>>,
88
89    /// Human-readable title for the field
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub title: Option<String>,
92
93    /// Field description
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub description: Option<String>,
96
97    // Numeric validation (added in 0.2.0)
98    /// Minimum value (inclusive) for numeric types
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub minimum: Option<f64>,
101
102    /// Maximum value (inclusive) for numeric types
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub maximum: Option<f64>,
105
106    /// Minimum value (exclusive) for numeric types
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub exclusive_minimum: Option<f64>,
109
110    /// Maximum value (exclusive) for numeric types
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub exclusive_maximum: Option<f64>,
113
114    /// Number must be a multiple of this value
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub multiple_of: Option<f64>,
117
118    // String validation (added in 0.2.0)
119    /// Minimum string length
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub min_length: Option<usize>,
122
123    /// Maximum string length
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub max_length: Option<usize>,
126
127    /// Predefined format for string validation
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub format: Option<StringFormat>,
130
131    // Array validation (added in 0.2.0)
132    /// Minimum number of array items
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub min_items: Option<usize>,
135
136    /// Maximum number of array items
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub max_items: Option<usize>,
139
140    /// Whether array items must be unique
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub unique_items: Option<bool>,
143
144    // Object validation (added in 0.2.0)
145    /// Whether additional properties are allowed in objects
146    #[serde(skip_serializing_if = "Option::is_none")]
147    pub additional_properties: Option<bool>,
148
149    // Default and examples (added in 0.2.0)
150    /// Default value for the field
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub default: Option<Value>,
153
154    /// Example values
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub examples: Option<Vec<Value>>,
157
158    // Other constraints (added in 0.2.0)
159    /// Field must have this exact value
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub r#const: Option<Value>,
162
163    /// Whether this field is deprecated
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub deprecated: Option<bool>,
166}
167
168/// Supported field types
169#[derive(Debug, Clone, Serialize, Deserialize)]
170#[serde(rename_all = "lowercase")]
171pub enum FieldType {
172    String,
173    Number,
174    Boolean,
175    Object,
176    Array,
177    Ref,
178    Any,
179}
180
181/// Supported string format validators
182#[derive(Debug, Clone, Serialize, Deserialize)]
183#[serde(rename_all = "lowercase")]
184pub enum StringFormat {
185    Email,
186    Uri,
187    Uuid,
188    Date,
189    #[serde(rename = "datetime")]
190    DateTime,
191    Time,
192    #[serde(rename = "ipv4")]
193    Ipv4,
194    #[serde(rename = "ipv6")]
195    Ipv6,
196    Hostname,
197    Regex,
198}
199
200// Keep for backward compatibility during migration
201#[derive(Debug, Serialize, Deserialize)]
202pub struct OutputConfiguration {
203    pub artifacts: Option<Vec<String>>,
204    pub directory: Option<String>,
205}
206
207#[derive(Debug, Serialize, Deserialize)]
208pub struct SourceDefinition {
209    pub path: String,
210    pub r#type: String,
211    pub include: Option<Vec<String>>,
212    pub exclude: Option<Vec<String>>,
213}