1use indexmap::IndexMap;
6use serde::{Deserialize, Serialize};
7use sha2::{Digest, Sha256};
8
9#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
11pub struct WesleyIR {
12 pub version: String,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub metadata: Option<Metadata>,
17 pub types: Vec<TypeDefinition>,
19}
20
21#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
23#[serde(rename_all = "camelCase")]
24pub struct Metadata {
25 pub source_hash: Option<String>,
27 pub generated_at: Option<String>,
29 #[serde(default, skip_serializing_if = "Vec::is_empty")]
31 pub units: Vec<UnitMeta>,
32}
33
34#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
36pub struct UnitMeta {
37 pub id: String,
39 pub package: String,
41 pub hash: String,
43}
44
45#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
47#[serde(rename_all = "camelCase")]
48pub struct TypeDefinition {
49 pub name: String,
51 pub kind: TypeKind,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub description: Option<String>,
56 pub directives: IndexMap<String, serde_json::Value>,
58 #[serde(default, skip_serializing_if = "Vec::is_empty")]
60 pub implements: Vec<String>,
61 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub fields: Vec<Field>,
64 #[serde(default, skip_serializing_if = "Vec::is_empty")]
66 pub enum_values: Vec<String>,
67 #[serde(default, skip_serializing_if = "Vec::is_empty")]
69 pub union_members: Vec<String>,
70}
71
72#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
74#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
75pub enum TypeKind {
76 Object,
78 Interface,
80 Union,
82 Enum,
84 Scalar,
86 InputObject,
88}
89
90#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
92#[serde(rename_all = "camelCase")]
93pub struct Field {
94 pub name: String,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub description: Option<String>,
99 pub r#type: TypeReference,
101 #[serde(default, skip_serializing_if = "Vec::is_empty")]
103 pub arguments: Vec<FieldArgument>,
104 pub directives: IndexMap<String, serde_json::Value>,
106}
107
108#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
110#[serde(rename_all = "camelCase")]
111pub struct FieldArgument {
112 pub name: String,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub description: Option<String>,
117 pub r#type: TypeReference,
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub default_value: Option<serde_json::Value>,
122 pub directives: IndexMap<String, serde_json::Value>,
124}
125
126#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
128#[serde(rename_all = "camelCase")]
129pub struct TypeReference {
130 pub base: String,
132 pub nullable: bool,
134 pub is_list: bool,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub list_item_nullable: Option<bool>,
139 #[serde(default, skip_serializing_if = "Vec::is_empty")]
141 pub list_wrappers: Vec<TypeListWrapper>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub leaf_nullable: Option<bool>,
145}
146
147#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
149#[serde(rename_all = "camelCase")]
150pub struct TypeListWrapper {
151 pub nullable: bool,
153}
154
155pub fn compute_registry_hash(ir: &WesleyIR) -> Result<String, serde_json::Error> {
157 let mut parity_ir = ir.clone();
158 parity_ir.metadata = None;
159
160 let json = to_canonical_json(&parity_ir)?;
161 Ok(compute_content_hash(&json))
162}
163
164pub fn compute_content_hash(content: &str) -> String {
166 let mut hasher = Sha256::new();
167 hasher.update(content.as_bytes());
168 let result = hasher.finalize();
169
170 hex::encode(result)
171}
172
173pub fn to_canonical_json<T: Serialize>(value: &T) -> Result<String, serde_json::Error> {
175 let val = serde_json::to_value(value)?;
176 let sorted_val = sort_json_value(val);
177 serde_json::to_string(&sorted_val)
178}
179
180fn sort_json_value(value: serde_json::Value) -> serde_json::Value {
181 match value {
182 serde_json::Value::Object(map) => {
183 let mut sorted_map = serde_json::Map::new();
184 let mut keys: Vec<String> = map.keys().cloned().collect();
185 keys.sort();
186 for key in keys {
187 if let Some(val) = map.get(&key) {
188 sorted_map.insert(key, sort_json_value(val.clone()));
189 }
190 }
191 serde_json::Value::Object(sorted_map)
192 }
193 serde_json::Value::Array(arr) => {
194 serde_json::Value::Array(arr.into_iter().map(sort_json_value).collect())
195 }
196 _ => value,
197 }
198}