1use hmd_core::{BlockDescriptor, MetadataField, MetadataFieldKind, ProfileDescriptor};
2use schemars::{schema_for, JsonSchema};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
6#[serde(rename_all = "snake_case")]
7pub enum EntryKind {
8 Research,
9 Plan,
10 Change,
11 Test,
12 Review,
13 Decision,
14 Blocker,
15 Handoff,
16}
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
19pub struct ProgressMeta {
20 pub id: String,
21 pub project: String,
22 pub status: String,
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
26pub struct EntryMeta {
27 pub id: String,
28 pub at: String,
29 pub actor: String,
30 pub kind: EntryKind,
31 pub summary: String,
32 pub corrects: Option<String>,
33 pub supersedes: Option<String>,
34}
35
36#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
37pub struct ChangeMeta {
38 pub files: Vec<String>,
39 pub scope: Option<String>,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
43pub struct TestMeta {
44 pub command: String,
45 pub result: Option<String>,
46}
47
48#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
49pub struct BlockerMeta {
50 pub id: String,
51 pub severity: Option<String>,
52 pub owner: Option<String>,
53 pub status: Option<String>,
54}
55
56#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
57pub struct NextMeta {
58 pub task: String,
59 pub priority: Option<String>,
60}
61
62#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
63#[serde(rename_all = "camelCase")]
64pub struct ProgressProfileSchema {
65 pub progress: Option<ProgressMeta>,
66 pub entry: Option<EntryMeta>,
67 pub change: Option<ChangeMeta>,
68 pub test: Option<TestMeta>,
69 pub blocker: Option<BlockerMeta>,
70 pub next: Option<NextMeta>,
71}
72
73const ENTRY_KINDS: &[&str] = &[
74 "research", "plan", "change", "test", "review", "decision", "blocker", "handoff",
75];
76
77const PROGRESS_FIELDS: &[MetadataField] = &[
78 MetadataField::required("id", MetadataFieldKind::String),
79 MetadataField::required("project", MetadataFieldKind::String),
80 MetadataField::required("status", MetadataFieldKind::String),
81];
82const ENTRY_FIELDS: &[MetadataField] = &[
83 MetadataField::required("id", MetadataFieldKind::String),
84 MetadataField::required("at", MetadataFieldKind::String),
85 MetadataField::required("actor", MetadataFieldKind::String),
86 MetadataField::required_enum("kind", ENTRY_KINDS),
87 MetadataField::required("summary", MetadataFieldKind::String),
88 MetadataField::optional("corrects", MetadataFieldKind::String),
89 MetadataField::optional("supersedes", MetadataFieldKind::String),
90];
91const CHANGE_FIELDS: &[MetadataField] = &[
92 MetadataField::required("files", MetadataFieldKind::StringArray),
93 MetadataField::optional("scope", MetadataFieldKind::String),
94];
95const TEST_FIELDS: &[MetadataField] = &[
96 MetadataField::required("command", MetadataFieldKind::String),
97 MetadataField::optional("result", MetadataFieldKind::String),
98];
99const BLOCKER_FIELDS: &[MetadataField] = &[
100 MetadataField::required("id", MetadataFieldKind::String),
101 MetadataField::optional("severity", MetadataFieldKind::String),
102 MetadataField::optional("owner", MetadataFieldKind::String),
103 MetadataField::optional("status", MetadataFieldKind::String),
104];
105const NEXT_FIELDS: &[MetadataField] = &[
106 MetadataField::required("task", MetadataFieldKind::String),
107 MetadataField::optional("priority", MetadataFieldKind::String),
108];
109
110const PROGRESS_CHILDREN: &[&str] = &["entry"];
111const ENTRY_CHILDREN: &[&str] = &["change", "test", "blocker", "next"];
112
113const BLOCKS: &[BlockDescriptor] = &[
114 BlockDescriptor {
115 block_type: "progress",
116 schema_id: "https://hmd.dev/schemas/progress@0.1/progress.schema.json",
117 fields: PROGRESS_FIELDS,
118 allowed_child_block_types: Some(PROGRESS_CHILDREN),
119 },
120 BlockDescriptor {
121 block_type: "entry",
122 schema_id: "https://hmd.dev/schemas/progress@0.1/entry.schema.json",
123 fields: ENTRY_FIELDS,
124 allowed_child_block_types: Some(ENTRY_CHILDREN),
125 },
126 BlockDescriptor {
127 block_type: "change",
128 schema_id: "https://hmd.dev/schemas/progress@0.1/change.schema.json",
129 fields: CHANGE_FIELDS,
130 allowed_child_block_types: None,
131 },
132 BlockDescriptor {
133 block_type: "test",
134 schema_id: "https://hmd.dev/schemas/progress@0.1/test.schema.json",
135 fields: TEST_FIELDS,
136 allowed_child_block_types: None,
137 },
138 BlockDescriptor {
139 block_type: "blocker",
140 schema_id: "https://hmd.dev/schemas/progress@0.1/blocker.schema.json",
141 fields: BLOCKER_FIELDS,
142 allowed_child_block_types: None,
143 },
144 BlockDescriptor {
145 block_type: "next",
146 schema_id: "https://hmd.dev/schemas/progress@0.1/next.schema.json",
147 fields: NEXT_FIELDS,
148 allowed_child_block_types: None,
149 },
150];
151
152pub const PROFILE: ProfileDescriptor = ProfileDescriptor {
153 id: "progress@0.1",
154 name: "progress",
155 version: "0.1",
156 source: "official",
157 blocks: BLOCKS,
158 reference_rules: &[],
159};
160
161pub fn descriptor() -> ProfileDescriptor {
162 PROFILE
163}
164
165pub fn register_profile() -> ProfileDescriptor {
166 descriptor()
167}
168
169pub fn json_schema() -> serde_json::Value {
170 serde_json::to_value(schema_for!(ProgressProfileSchema)).expect("serializes schema")
171}