1use serde_json::{Value, json};
7
8use crate::output::OutputSchema;
9
10pub fn get_output_schema(command: &str) -> Option<OutputSchema> {
12 let (success, error) = match command {
13 "compile" => (compile_success_schema(), error_schema()),
14 "validate" => (validate_success_schema(), validation_error_schema()),
15 "lint" => (lint_success_schema(), error_schema()),
16 "analyze" => (analyze_success_schema(), error_schema()),
17 "explain" => (explain_success_schema(), error_schema()),
18 "cost" => (cost_success_schema(), error_schema()),
19 "dependency-graph" => (dependency_graph_success_schema(), error_schema()),
20 _ => return None,
21 };
22
23 Some(OutputSchema {
24 command: command.to_string(),
25 schema_version: "1.0".to_string(),
26 format: "json".to_string(),
27 success,
28 error,
29 })
30}
31
32pub fn list_schema_commands() -> Vec<&'static str> {
34 vec![
35 "compile",
36 "validate",
37 "lint",
38 "analyze",
39 "explain",
40 "cost",
41 "dependency-graph",
42 ]
43}
44
45fn compile_success_schema() -> Value {
46 json!({
47 "type": "object",
48 "required": ["status", "command", "data"],
49 "properties": {
50 "status": {
51 "type": "string",
52 "const": "success"
53 },
54 "command": {
55 "type": "string",
56 "const": "compile"
57 },
58 "data": {
59 "type": "object",
60 "properties": {
61 "output_file": {
62 "type": "string",
63 "description": "Path to the generated schema.compiled.json"
64 },
65 "types_count": {
66 "type": "integer",
67 "description": "Number of types compiled"
68 },
69 "queries_count": {
70 "type": "integer",
71 "description": "Number of queries compiled"
72 },
73 "mutations_count": {
74 "type": "integer",
75 "description": "Number of mutations compiled"
76 }
77 }
78 },
79 "warnings": {
80 "type": "array",
81 "items": { "type": "string" }
82 }
83 }
84 })
85}
86
87fn validate_success_schema() -> Value {
88 json!({
89 "type": "object",
90 "required": ["status", "command", "data"],
91 "properties": {
92 "status": {
93 "type": "string",
94 "enum": ["success", "validation-failed"]
95 },
96 "command": {
97 "type": "string",
98 "const": "validate"
99 },
100 "data": {
101 "type": "object",
102 "properties": {
103 "types_validated": {
104 "type": "integer"
105 },
106 "cycles_detected": {
107 "type": "array",
108 "items": {
109 "type": "array",
110 "items": { "type": "string" }
111 }
112 },
113 "unused_types": {
114 "type": "array",
115 "items": { "type": "string" }
116 }
117 }
118 },
119 "errors": {
120 "type": "array",
121 "items": { "type": "string" },
122 "description": "Validation errors (when status is validation-failed)"
123 },
124 "warnings": {
125 "type": "array",
126 "items": { "type": "string" }
127 }
128 }
129 })
130}
131
132fn validation_error_schema() -> Value {
133 json!({
134 "type": "object",
135 "required": ["status", "command", "errors"],
136 "properties": {
137 "status": {
138 "type": "string",
139 "const": "validation-failed"
140 },
141 "command": {
142 "type": "string"
143 },
144 "errors": {
145 "type": "array",
146 "items": { "type": "string" },
147 "minItems": 1
148 }
149 }
150 })
151}
152
153fn lint_success_schema() -> Value {
154 json!({
155 "type": "object",
156 "required": ["status", "command", "data"],
157 "properties": {
158 "status": {
159 "type": "string",
160 "const": "success"
161 },
162 "command": {
163 "type": "string",
164 "const": "lint"
165 },
166 "data": {
167 "type": "object",
168 "properties": {
169 "audits": {
170 "type": "object",
171 "additionalProperties": {
172 "type": "object",
173 "properties": {
174 "issues": {
175 "type": "array",
176 "items": {
177 "type": "object",
178 "properties": {
179 "severity": { "type": "string", "enum": ["critical", "warning", "info"] },
180 "message": { "type": "string" },
181 "location": { "type": "string" }
182 }
183 }
184 }
185 }
186 }
187 },
188 "summary": {
189 "type": "object",
190 "properties": {
191 "critical": { "type": "integer" },
192 "warning": { "type": "integer" },
193 "info": { "type": "integer" }
194 }
195 }
196 }
197 }
198 }
199 })
200}
201
202fn analyze_success_schema() -> Value {
203 json!({
204 "type": "object",
205 "required": ["status", "command", "data"],
206 "properties": {
207 "status": {
208 "type": "string",
209 "const": "success"
210 },
211 "command": {
212 "type": "string",
213 "const": "analyze"
214 },
215 "data": {
216 "type": "object",
217 "properties": {
218 "recommendations": {
219 "type": "array",
220 "items": {
221 "type": "object",
222 "properties": {
223 "category": {
224 "type": "string",
225 "enum": ["performance", "security", "federation", "complexity", "caching", "indexing"]
226 },
227 "severity": { "type": "string" },
228 "message": { "type": "string" },
229 "suggestion": { "type": "string" }
230 }
231 }
232 }
233 }
234 }
235 }
236 })
237}
238
239fn explain_success_schema() -> Value {
240 json!({
241 "type": "object",
242 "required": ["status", "command", "data"],
243 "properties": {
244 "status": {
245 "type": "string",
246 "const": "success"
247 },
248 "command": {
249 "type": "string",
250 "const": "explain"
251 },
252 "data": {
253 "type": "object",
254 "properties": {
255 "query": { "type": "string" },
256 "execution_plan": {
257 "type": "object",
258 "properties": {
259 "steps": {
260 "type": "array",
261 "items": { "type": "string" }
262 }
263 }
264 },
265 "sql": { "type": "string" },
266 "complexity": {
267 "type": "object",
268 "properties": {
269 "depth": { "type": "integer" },
270 "field_count": { "type": "integer" },
271 "score": { "type": "integer" }
272 }
273 }
274 }
275 }
276 }
277 })
278}
279
280fn cost_success_schema() -> Value {
281 json!({
282 "type": "object",
283 "required": ["status", "command", "data"],
284 "properties": {
285 "status": {
286 "type": "string",
287 "const": "success"
288 },
289 "command": {
290 "type": "string",
291 "const": "cost"
292 },
293 "data": {
294 "type": "object",
295 "required": ["depth", "field_count", "score"],
296 "properties": {
297 "depth": {
298 "type": "integer",
299 "description": "Maximum nesting depth of the query"
300 },
301 "field_count": {
302 "type": "integer",
303 "description": "Total number of fields requested"
304 },
305 "score": {
306 "type": "integer",
307 "description": "Calculated complexity score"
308 }
309 }
310 }
311 }
312 })
313}
314
315fn dependency_graph_success_schema() -> Value {
316 json!({
317 "type": "object",
318 "required": ["status", "command", "data"],
319 "properties": {
320 "status": {
321 "type": "string",
322 "const": "success"
323 },
324 "command": {
325 "type": "string",
326 "const": "dependency-graph"
327 },
328 "data": {
329 "type": "object",
330 "properties": {
331 "format": {
332 "type": "string",
333 "enum": ["json", "dot", "mermaid", "d2", "console"]
334 },
335 "graph": {
336 "type": "object",
337 "description": "Graph data (format depends on output format)",
338 "properties": {
339 "nodes": {
340 "type": "array",
341 "items": {
342 "type": "object",
343 "properties": {
344 "name": { "type": "string" },
345 "type": { "type": "string" }
346 }
347 }
348 },
349 "edges": {
350 "type": "array",
351 "items": {
352 "type": "object",
353 "properties": {
354 "from": { "type": "string" },
355 "to": { "type": "string" },
356 "relationship": { "type": "string" }
357 }
358 }
359 }
360 }
361 },
362 "cycles": {
363 "type": "array",
364 "items": {
365 "type": "array",
366 "items": { "type": "string" }
367 }
368 },
369 "unused_types": {
370 "type": "array",
371 "items": { "type": "string" }
372 }
373 }
374 }
375 }
376 })
377}
378
379fn error_schema() -> Value {
380 json!({
381 "type": "object",
382 "required": ["status", "command", "message", "code"],
383 "properties": {
384 "status": {
385 "type": "string",
386 "const": "error"
387 },
388 "command": {
389 "type": "string"
390 },
391 "message": {
392 "type": "string",
393 "description": "Human-readable error message"
394 },
395 "code": {
396 "type": "string",
397 "description": "Machine-readable error code"
398 }
399 }
400 })
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406
407 #[test]
408 fn test_get_output_schema_compile() {
409 let schema = get_output_schema("compile");
410 assert!(schema.is_some());
411 let schema = schema.unwrap();
412 assert_eq!(schema.command, "compile");
413 assert_eq!(schema.format, "json");
414 }
415
416 #[test]
417 fn test_get_output_schema_unknown() {
418 let schema = get_output_schema("unknown-command");
419 assert!(schema.is_none());
420 }
421
422 #[test]
423 fn test_list_schema_commands() {
424 let commands = list_schema_commands();
425 assert!(commands.contains(&"compile"));
426 assert!(commands.contains(&"validate"));
427 assert!(commands.contains(&"lint"));
428 }
429
430 #[test]
431 fn test_success_schema_structure() {
432 let schema = get_output_schema("cost").unwrap();
433 let success = &schema.success;
434
435 assert_eq!(success["type"], "object");
436 assert!(success["required"].is_array());
437 assert!(success["properties"].is_object());
438 }
439
440 #[test]
441 fn test_error_schema_structure() {
442 let schema = get_output_schema("compile").unwrap();
443 let error = &schema.error;
444
445 assert_eq!(error["type"], "object");
446 assert!(error["properties"]["message"].is_object());
447 assert!(error["properties"]["code"].is_object());
448 }
449}