Skip to main content

onetaskgraph_core/
schema.rs

1//! The JSON Schema bundle both SDKs are generated from.
2//!
3//! It is emitted by `onetaskgraph schema` rather than committed, so the schema a
4//! consumer generates against can never drift from the types this binary actually
5//! serialises: they are the same types.
6
7use std::collections::BTreeMap;
8
9use onetaskgraph_plugin_api::{
10    Capabilities, DependencyEdge, DependencyEndpoint, DependencyKind, Direction, Health, ItemKind,
11    Label, Page, PageRequest, Project, ProjectQuery, Repository, SourceError, Status,
12    StatusCategory, Task, TaskQuery, TextFields,
13};
14use schemars::{Schema, schema_for};
15use serde_json::{Value, json};
16
17use crate::config::{EffectiveConfig, Origin, OutputFormat, Setting};
18use crate::registry::registry;
19use crate::secrets::{CredentialLayer, ResolvedCredential, SecretsReport};
20use crate::{
21    CopyAction, CopyOutcome, CopyReport, GlobalId, PageToken, Predicate, Qualified, QualifiedEdge,
22    QualifiedEndpoint, QueryPlan, QueryResponse, SearchHit, SearchKind, SourceFailure,
23    SourceListing, SourcePlan,
24};
25
26/// The bundle's own version, bumped whenever a root is added, removed or renamed.
27///
28/// Consumers generate code from this document, so the version is part of the
29/// contract rather than a convenience: an SDK can refuse a bundle it was not
30/// generated against instead of silently emitting the wrong models.
31///
32/// Which roots each version brought is what `git log` answers; what this number owes a
33/// reader is that it moves whenever [`schema_bundle`] below gains, loses or renames one.
34pub const SCHEMA_BUNDLE_VERSION: u32 = 7;
35
36/// Every contract root, keyed by name, plus each registered plugin's config schema.
37#[must_use]
38pub fn schema_bundle() -> Value {
39    let mut roots: BTreeMap<&'static str, Schema> = BTreeMap::new();
40
41    roots.insert("Task", schema_for!(Task));
42    roots.insert("Project", schema_for!(Project));
43    roots.insert("Label", schema_for!(Label));
44    roots.insert("Status", schema_for!(Status));
45    roots.insert("StatusCategory", schema_for!(StatusCategory));
46    roots.insert("DependencyEdge", schema_for!(DependencyEdge));
47    roots.insert("DependencyEndpoint", schema_for!(DependencyEndpoint));
48    roots.insert("QualifiedEndpoint", schema_for!(QualifiedEndpoint));
49    roots.insert("ItemKind", schema_for!(ItemKind));
50    roots.insert("Repository", schema_for!(Repository));
51    roots.insert("DependencyKind", schema_for!(DependencyKind));
52    roots.insert("Direction", schema_for!(Direction));
53    // Roots of their own although both are reachable inside `TaskQuery`'s definitions,
54    // which is enough for a generator and not enough for a reconciliation: the command
55    // line spells both deliberately differently (`both` for `title-or-content`, `task`
56    // for `tasks`), so a variant added to either would leave the command line quietly
57    // unable to name it. A root apiece gives that gate one document to read.
58    roots.insert("TextFields", schema_for!(TextFields));
59    roots.insert("SearchKind", schema_for!(SearchKind));
60
61    roots.insert("TaskQuery", schema_for!(TaskQuery));
62    roots.insert("ProjectQuery", schema_for!(ProjectQuery));
63    roots.insert("PageRequest", schema_for!(PageRequest));
64    roots.insert("PageOfTask", schema_for!(Page<Task>));
65    roots.insert("PageOfProject", schema_for!(Page<Project>));
66    roots.insert("PageOfLabel", schema_for!(Page<Label>));
67    roots.insert("PageOfDependencyEdge", schema_for!(Page<DependencyEdge>));
68
69    roots.insert("Capabilities", schema_for!(Capabilities));
70    roots.insert("Health", schema_for!(Health));
71    roots.insert("SourceError", schema_for!(SourceError));
72
73    roots.insert("GlobalId", schema_for!(GlobalId));
74    roots.insert("PageToken", schema_for!(PageToken));
75    roots.insert("QueryPlan", schema_for!(QueryPlan));
76    roots.insert("SourcePlan", schema_for!(SourcePlan));
77    roots.insert("Predicate", schema_for!(Predicate));
78    roots.insert("SourceFailure", schema_for!(SourceFailure));
79    roots.insert("QualifiedTask", schema_for!(Qualified<Task>));
80    roots.insert("QualifiedProject", schema_for!(Qualified<Project>));
81    roots.insert("QualifiedLabel", schema_for!(Qualified<Label>));
82    roots.insert("QualifiedEdge", schema_for!(QualifiedEdge));
83    roots.insert("SearchHit", schema_for!(SearchHit));
84    roots.insert("SourceListing", schema_for!(SourceListing));
85    roots.insert("SourceListings", schema_for!(Vec<SourceListing>));
86    roots.insert(
87        "QueryResponseOfQualifiedTask",
88        schema_for!(QueryResponse<Qualified<Task>>),
89    );
90    roots.insert(
91        "QueryResponseOfQualifiedProject",
92        schema_for!(QueryResponse<Qualified<Project>>),
93    );
94    roots.insert(
95        "QueryResponseOfQualifiedLabel",
96        schema_for!(QueryResponse<Qualified<Label>>),
97    );
98    roots.insert(
99        "QueryResponseOfQualifiedEdge",
100        schema_for!(QueryResponse<QualifiedEdge>),
101    );
102    roots.insert(
103        "QueryResponseOfSearchHit",
104        schema_for!(QueryResponse<SearchHit>),
105    );
106
107    roots.insert("CopyReport", schema_for!(CopyReport));
108    roots.insert("CopyOutcome", schema_for!(CopyOutcome));
109    roots.insert("CopyAction", schema_for!(CopyAction));
110
111    roots.insert("EffectiveConfig", schema_for!(EffectiveConfig));
112    roots.insert("Setting", schema_for!(Setting));
113    roots.insert("Origin", schema_for!(Origin));
114    roots.insert("OutputFormat", schema_for!(OutputFormat));
115    roots.insert("SecretsReport", schema_for!(SecretsReport));
116    roots.insert("ResolvedCredential", schema_for!(ResolvedCredential));
117    roots.insert("CredentialLayer", schema_for!(CredentialLayer));
118
119    let plugins: BTreeMap<String, Schema> = registry()
120        .iter()
121        .map(|plugin| (plugin.kind().to_owned(), plugin.config_schema()))
122        .collect();
123
124    json!({
125        "version": SCHEMA_BUNDLE_VERSION,
126        "roots": roots,
127        "plugin_config": plugins,
128    })
129}