graphql_schema_diff/
lib.rs1#![doc = include_str!("../README.md")]
2
3pub mod path;
4
5mod change;
6mod patch;
7mod state;
8mod traverse_schemas;
9
10pub use self::{
11 change::{Change, ChangeKind, Span},
12 patch::{PatchedSchema, patch},
13};
14
15use self::state::*;
16use cynic_parser::type_system as ast;
17use std::collections::HashMap;
18
19pub fn diff_asts(
21 source: Option<&cynic_parser::TypeSystemDocument>,
22 target: Option<&cynic_parser::TypeSystemDocument>,
23) -> Vec<Change> {
24 let mut state = DiffState::default();
25
26 traverse_schemas::traverse_schemas([source, target], &mut state);
27
28 state.into_changes()
29}
30
31pub fn diff(source: &str, target: &str) -> Result<Vec<Change>, cynic_parser::Error> {
33 let [source, target] = [source, target].map(|sdl| -> Result<_, cynic_parser::Error> {
34 if sdl.trim().is_empty() {
35 Ok(None)
36 } else {
37 Ok(Some(cynic_parser::parse_type_system_document(sdl)?))
38 }
39 });
40 let [source, target] = [source?, target?];
41
42 Ok(diff_asts(source.as_ref(), target.as_ref()))
43}
44
45pub fn resolve_spans<'a: 'b, 'b>(
47 source: &'a str,
48 target: &'a str,
49 changes: &'b [Change],
50) -> impl Iterator<Item = &'a str> + 'b {
51 changes.iter().map(move |change| {
52 let relevant_schema = match change.kind {
53 ChangeKind::ChangeQueryType => target,
54 ChangeKind::ChangeMutationType => target,
55 ChangeKind::ChangeSubscriptionType => target,
56 ChangeKind::RemoveObjectType => source,
57 ChangeKind::AddObjectType => target,
58 ChangeKind::AddInterfaceImplementation => target,
59 ChangeKind::RemoveInterfaceImplementation => source,
60 ChangeKind::ChangeFieldType => target,
61 ChangeKind::RemoveField => source,
62 ChangeKind::AddField => target,
63 ChangeKind::AddUnion => target,
64 ChangeKind::RemoveUnion => source,
65 ChangeKind::AddUnionMember => target,
66 ChangeKind::RemoveUnionMember => source,
67 ChangeKind::AddEnum => target,
68 ChangeKind::RemoveEnum => source,
69 ChangeKind::AddEnumValue => target,
70 ChangeKind::RemoveEnumValue => source,
71 ChangeKind::AddScalar => target,
72 ChangeKind::RemoveScalar => source,
73 ChangeKind::AddInterface => target,
74 ChangeKind::RemoveInterface => source,
75 ChangeKind::AddDirectiveDefinition => target,
76 ChangeKind::RemoveDirectiveDefinition => source,
77 ChangeKind::AddSchemaDefinition => target,
78 ChangeKind::AddSchemaExtension => target,
79 ChangeKind::RemoveSchemaExtension => source,
80 ChangeKind::RemoveSchemaDefinition => source,
81 ChangeKind::AddInputObject => target,
82 ChangeKind::RemoveInputObject => source,
83 ChangeKind::AddFieldArgument => target,
84 ChangeKind::RemoveFieldArgument => source,
85 ChangeKind::AddFieldArgumentDefault => target,
86 ChangeKind::RemoveFieldArgumentDefault => source,
87 ChangeKind::ChangeFieldArgumentDefault => target,
88 ChangeKind::ChangeFieldArgumentType => target,
89 ChangeKind::AddDirective => target,
90 ChangeKind::RemoveDirective => source,
91 ChangeKind::ChangeDescription => target,
92 };
93
94 &relevant_schema[change.span]
95 })
96}
97
98pub fn resolve_source_spans<'a: 'b, 'b>(
103 source: &'a str,
104 changes: &'b [Change],
105) -> impl Iterator<Item = Option<&'a str>> + 'b {
106 changes.iter().map(move |change| Some(&source[change.source_span?]))
107}