use crate::diagnostics::Diagnostics;
use async_graphql_parser::{types as ast, Pos, Positioned};
use async_graphql_value::Name;
use std::collections::HashMap;
type AstField = Positioned<ast::FieldDefinition>;
pub(crate) struct Context<'a> {
pub(crate) sdl: &'a str,
pub(crate) definition_names: HashMap<&'a str, &'a Positioned<ast::TypeDefinition>>,
pub(crate) directive_names: HashMap<&'a str, &'a Positioned<ast::DirectiveDefinition>>,
pub(crate) diagnostics: Diagnostics,
pub(crate) options: crate::Options,
pub(crate) schema_definition: Option<SchemaDefinition<'a>>,
pub(crate) extended_fields: HashMap<&'a str, Vec<&'a [AstField]>>,
pub(crate) extended_unions: HashMap<&'a str, Vec<&'a [Positioned<Name>]>>,
pub(crate) extended_interface_implementations: HashMap<&'a str, Vec<&'a Positioned<Name>>>,
pub(crate) extended_enums: HashMap<&'a str, Vec<&'a [Positioned<ast::EnumValueDefinition>]>>,
strings_buf: HashMap<&'a str, usize>,
}
impl<'a> Context<'a> {
pub(crate) fn new(
sdl: &'a str,
definition_names: HashMap<&'a str, &'a Positioned<ast::TypeDefinition>>,
diagnostics: Diagnostics,
options: crate::Options,
) -> Self {
Context {
sdl,
definition_names,
diagnostics,
options,
schema_definition: None,
strings_buf: HashMap::default(),
directive_names: HashMap::default(),
extended_interface_implementations: HashMap::default(),
extended_fields: HashMap::default(),
extended_unions: HashMap::default(),
extended_enums: HashMap::default(),
}
}
pub(crate) fn with_enum_values<F>(
&mut self,
enum_name: &str,
base_values: &'a [Positioned<ast::EnumValueDefinition>],
mut handler: F,
) where
F: FnMut(&mut Self, &[&'a Positioned<ast::EnumValueDefinition>]),
{
let all_values: Vec<_> = base_values
.iter()
.chain(
self.extended_enums
.get(enum_name)
.into_iter()
.flat_map(|vecs| vecs.iter())
.flat_map(|values| values.iter()),
)
.collect();
handler(self, &all_values);
}
pub(crate) fn with_union_members<F>(
&mut self,
union_name: &str,
base_values: &'a [Positioned<Name>],
mut handler: F,
) where
F: FnMut(&mut Self, &[&'a Positioned<Name>]),
{
let all_values: Vec<_> = base_values
.iter()
.chain(
self.extended_unions
.get(union_name)
.into_iter()
.flat_map(|vecs| vecs.iter())
.flat_map(|values| values.iter()),
)
.collect();
handler(self, &all_values);
}
pub(crate) fn with_fields<F>(&mut self, name: &str, base_fields: &'a [AstField], mut handler: F)
where
F: FnMut(&mut Self, &[&'a AstField]),
{
let all_fields: Vec<_> = base_fields
.iter()
.chain(
self.extended_fields
.get(name)
.into_iter()
.flat_map(|fields| fields.iter())
.flat_map(|f| f.iter()),
)
.collect();
handler(self, &all_fields);
}
pub(crate) fn with_implements(
&mut self,
type_name: &str,
base_implements: &'a [Positioned<Name>],
mut handler: impl FnMut(&mut Self, &[&'a Positioned<Name>]),
) {
let extended = self
.extended_interface_implementations
.get(type_name)
.into_iter()
.flatten()
.copied();
let implements: Vec<_> = base_implements.iter().chain(extended).collect();
handler(self, &implements);
}
pub(crate) fn miette_pos(&self, pos: async_graphql_parser::Pos) -> miette::SourceOffset {
miette::SourceOffset::from_location(self.sdl, pos.line, pos.column)
}
pub(crate) fn push_error(&mut self, err: miette::Report) {
self.diagnostics.errors.push(err.with_source_code(self.sdl.to_owned()));
}
pub(crate) fn find_duplicates<F>(&mut self, names: impl Iterator<Item = &'a str>, mut handle_duplicates: F)
where
F: FnMut(&mut Self, usize, usize),
{
self.strings_buf.clear();
for (idx, name) in names.enumerate() {
if let Some(previous) = self.strings_buf.insert(name, idx) {
handle_duplicates(self, previous, idx);
}
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct SchemaDefinition<'a> {
pub(crate) pos: Pos,
pub(crate) directives: &'a [Positioned<ast::ConstDirective>],
pub(crate) query: Option<&'a str>,
pub(crate) mutation: Option<&'a str>,
pub(crate) subscription: Option<&'a str>,
}