1use std::collections::BTreeMap;
12
13use serde::{Deserialize, Serialize};
14
15use crate::edges::{
16 CoAuthorityItem, ConstrainItem, ExtendItem, Origin, ReferenceItem, RefineItem, SupersedeItem,
17};
18use crate::frontmatter::{Implementation, Risk, Status};
19use crate::unit::Unit;
20
21#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct Registry {
25 pub spec_version: String,
27 pub build: Build,
28 pub specs: Vec<SpecRecord>,
29 pub validation: ValidationReport,
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct Build {
37 pub compiler_id: String,
38 pub compiler_version: String,
39 pub input_root: String,
41 pub content_hash: String,
43}
44
45#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
47#[serde(rename_all = "camelCase")]
48pub struct SpecRecord {
49 pub id: String,
51 pub title: String,
52 pub status: Status,
53 pub created: String,
54 pub summary: String,
55 pub spec_path: String,
57
58 #[serde(default, skip_serializing_if = "Vec::is_empty")]
60 pub authors: Vec<String>,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub owner: Option<String>,
63 #[serde(default, skip_serializing_if = "Option::is_none")]
64 pub kind: Option<String>,
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub domain: Option<String>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub risk: Option<Risk>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub implementation: Option<Implementation>,
71 #[serde(default, skip_serializing_if = "Vec::is_empty")]
72 pub depends_on: Vec<String>,
73 #[serde(default, skip_serializing_if = "Vec::is_empty")]
74 pub code_aliases: Vec<String>,
75 #[serde(default, skip_serializing_if = "Option::is_none")]
76 pub feature_branch: Option<String>,
77 #[serde(default, skip_serializing_if = "Vec::is_empty")]
79 pub section_headings: Vec<String>,
80
81 #[serde(default, skip_serializing_if = "Vec::is_empty")]
83 pub establishes: Vec<Unit>,
84 #[serde(default, skip_serializing_if = "Vec::is_empty")]
85 pub extends: Vec<ExtendItem>,
86 #[serde(default, skip_serializing_if = "Vec::is_empty")]
87 pub refines: Vec<RefineItem>,
88 #[serde(default, skip_serializing_if = "Vec::is_empty")]
91 pub supersedes: Vec<SupersedeItem>,
92 #[serde(default, skip_serializing_if = "Vec::is_empty")]
93 pub amends: Vec<String>,
94 #[serde(default, skip_serializing_if = "Vec::is_empty")]
95 pub co_authority: Vec<CoAuthorityItem>,
96 #[serde(default, skip_serializing_if = "Vec::is_empty")]
97 pub constrains: Vec<ConstrainItem>,
98 #[serde(default, skip_serializing_if = "Vec::is_empty")]
99 pub references: Vec<ReferenceItem>,
100
101 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub superseded_by: Option<String>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
105 pub retirement_rationale: Option<String>,
106 #[serde(default, skip_serializing_if = "Vec::is_empty")]
107 pub amends_sections: Vec<String>,
108 #[serde(default, skip_serializing_if = "Vec::is_empty")]
109 pub unamendable: Vec<String>,
110 #[serde(default, skip_serializing_if = "Option::is_none")]
111 pub amendment_record: Option<String>,
112
113 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub origin: Option<Origin>,
116
117 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
121 pub extra_frontmatter: BTreeMap<String, serde_json::Value>,
122}
123
124#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct RegistrySpecShard {
139 pub spec_version: String,
141 pub shard_hash: String,
145 pub record: SpecRecord,
147 #[serde(default, skip_serializing_if = "Vec::is_empty")]
153 pub local_violations: Vec<Violation>,
154}
155
156#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
161#[serde(rename_all = "camelCase")]
162pub struct BuildMeta {
163 pub schema_version: String,
164 pub built_at: String,
165 pub compiler_id: String,
166 pub compiler_version: String,
167}
168
169#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
171#[serde(rename_all = "lowercase")]
172pub enum Severity {
173 Error,
174 Warning,
175 Info,
176}
177
178#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
180#[serde(rename_all = "camelCase")]
181pub struct Violation {
182 pub code: String,
184 pub severity: Severity,
185 pub message: String,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub path: Option<String>,
188}
189
190#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct ValidationReport {
195 pub passed: bool,
196 #[serde(default)]
197 pub violations: Vec<Violation>,
198}
199
200impl ValidationReport {
201 pub fn from_violations(violations: Vec<Violation>) -> Self {
203 let passed = !violations.iter().any(|v| v.severity == Severity::Error);
204 ValidationReport { passed, violations }
205 }
206}