1use hmd_core::{
2 BlockDescriptor, MetadataField, MetadataFieldKind, ProfileDescriptor, ReferenceRule,
3 ReferenceValueKind,
4};
5use schemars::{schema_for, JsonSchema};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
9#[serde(rename_all = "snake_case")]
10pub enum TaskStatus {
11 Todo,
12 Doing,
13 Blocked,
14 Review,
15 Done,
16 Cancelled,
17}
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
20pub struct TaskMeta {
21 pub id: String,
22 pub title: String,
23 pub status: TaskStatus,
24 pub priority: Option<String>,
25 pub labels: Option<Vec<String>>,
26 pub milestone: Option<String>,
27 pub depends_on: Option<Vec<String>>,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
31pub struct CheckMeta {
32 pub id: Option<String>,
33 pub title: Option<String>,
34 pub status: Option<TaskStatus>,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
38pub struct MilestoneMeta {
39 pub id: String,
40 pub title: String,
41 pub due: Option<String>,
42}
43
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
45pub struct DependencyMeta {
46 pub from: String,
47 pub to: String,
48 pub kind: Option<String>,
49}
50
51#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
52pub struct LabelMeta {
53 pub id: String,
54 pub color: Option<String>,
55}
56
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
58#[serde(rename_all = "camelCase")]
59pub struct TodoProfileSchema {
60 pub task: Option<TaskMeta>,
61 pub check: Option<CheckMeta>,
62 pub milestone: Option<MilestoneMeta>,
63 pub dependency: Option<DependencyMeta>,
64 pub label: Option<LabelMeta>,
65}
66
67const TASK_STATUSES: &[&str] = &["todo", "doing", "blocked", "review", "done", "cancelled"];
68
69const TASK_FIELDS: &[MetadataField] = &[
70 MetadataField::required("id", MetadataFieldKind::String),
71 MetadataField::required("title", MetadataFieldKind::String),
72 MetadataField::required_enum("status", TASK_STATUSES),
73 MetadataField::optional("priority", MetadataFieldKind::String),
74 MetadataField::optional("labels", MetadataFieldKind::StringArray),
75 MetadataField::optional("milestone", MetadataFieldKind::String),
76 MetadataField::optional("depends_on", MetadataFieldKind::StringArray),
77];
78const CHECK_FIELDS: &[MetadataField] = &[
79 MetadataField::optional("id", MetadataFieldKind::String),
80 MetadataField::optional("title", MetadataFieldKind::String),
81 MetadataField::optional_enum("status", TASK_STATUSES),
82];
83const MILESTONE_FIELDS: &[MetadataField] = &[
84 MetadataField::required("id", MetadataFieldKind::String),
85 MetadataField::required("title", MetadataFieldKind::String),
86 MetadataField::optional("due", MetadataFieldKind::String),
87];
88const DEPENDENCY_FIELDS: &[MetadataField] = &[
89 MetadataField::required("from", MetadataFieldKind::String),
90 MetadataField::required("to", MetadataFieldKind::String),
91 MetadataField::optional("kind", MetadataFieldKind::String),
92];
93const LABEL_FIELDS: &[MetadataField] = &[
94 MetadataField::required("id", MetadataFieldKind::String),
95 MetadataField::optional("color", MetadataFieldKind::String),
96];
97
98const BLOCKS: &[BlockDescriptor] = &[
99 BlockDescriptor {
100 block_type: "task",
101 schema_id: "https://hmd.dev/schemas/todo@0.1/task.schema.json",
102 fields: TASK_FIELDS,
103 allowed_child_block_types: None,
104 },
105 BlockDescriptor {
106 block_type: "check",
107 schema_id: "https://hmd.dev/schemas/todo@0.1/check.schema.json",
108 fields: CHECK_FIELDS,
109 allowed_child_block_types: None,
110 },
111 BlockDescriptor {
112 block_type: "milestone",
113 schema_id: "https://hmd.dev/schemas/todo@0.1/milestone.schema.json",
114 fields: MILESTONE_FIELDS,
115 allowed_child_block_types: None,
116 },
117 BlockDescriptor {
118 block_type: "dependency",
119 schema_id: "https://hmd.dev/schemas/todo@0.1/dependency.schema.json",
120 fields: DEPENDENCY_FIELDS,
121 allowed_child_block_types: None,
122 },
123 BlockDescriptor {
124 block_type: "label",
125 schema_id: "https://hmd.dev/schemas/todo@0.1/label.schema.json",
126 fields: LABEL_FIELDS,
127 allowed_child_block_types: None,
128 },
129];
130
131const REFERENCE_RULES: &[ReferenceRule] = &[ReferenceRule {
132 block_type: "task",
133 field: "depends_on",
134 target_block_type: "task",
135 value_kind: ReferenceValueKind::StringArray,
136}];
137
138pub const PROFILE: ProfileDescriptor = ProfileDescriptor {
139 id: "todo@0.1",
140 name: "todo",
141 version: "0.1",
142 source: "official",
143 blocks: BLOCKS,
144 reference_rules: REFERENCE_RULES,
145};
146
147pub fn descriptor() -> ProfileDescriptor {
148 PROFILE
149}
150
151pub fn register_profile() -> ProfileDescriptor {
152 descriptor()
153}
154
155pub fn json_schema() -> serde_json::Value {
156 serde_json::to_value(schema_for!(TodoProfileSchema)).expect("serializes schema")
157}