use crate::ast;
use crate::collections::IndexSet;
use crate::parser::SourceSpan;
use crate::schema::validation::BuiltInScalars;
use crate::schema::ComponentName;
use crate::schema::InterfaceType;
use crate::schema::Name;
use crate::validation::diagnostics::DiagnosticData;
use crate::validation::field::validate_field_definitions;
use crate::validation::DiagnosticList;
use crate::Node;
pub(crate) fn validate_interface_definition(
diagnostics: &mut DiagnosticList,
schema: &crate::Schema,
built_in_scalars: &mut BuiltInScalars,
interface: &Node<InterfaceType>,
) {
super::directive::validate_directives(
diagnostics,
Some(schema),
interface.directives.iter_ast(),
ast::DirectiveLocation::Interface,
Default::default(),
);
for implements_interface in &interface.implements_interfaces {
if *implements_interface == interface.name {
diagnostics.push(
implements_interface.location(),
DiagnosticData::RecursiveInterfaceDefinition {
name: implements_interface.name.clone(),
},
);
}
}
validate_field_definitions(diagnostics, schema, built_in_scalars, &interface.fields);
if interface.fields.is_empty() {
diagnostics.push(
interface.location(),
DiagnosticData::EmptyFieldSet {
type_name: interface.name.clone(),
type_location: interface.location(),
extensions_locations: interface
.extensions()
.iter()
.map(|ext| ext.location())
.collect(),
},
);
}
validate_implements_interfaces(
diagnostics,
schema,
&interface.name,
interface.location(),
&interface.implements_interfaces,
);
for implements_interface in &interface.implements_interfaces {
if let Some(super_interface) = schema.get_interface(implements_interface) {
for super_field in super_interface.fields.values() {
if interface.fields.contains_key(&super_field.name) {
continue;
}
diagnostics.push(
interface.location(),
DiagnosticData::MissingInterfaceField {
name: interface.name.clone(),
implements_location: implements_interface.location(),
interface: implements_interface.name.clone(),
field: super_field.name.clone(),
field_location: super_field.location(),
},
);
}
}
}
}
pub(crate) fn validate_implements_interfaces(
diagnostics: &mut DiagnosticList,
schema: &crate::Schema,
implementor_name: &Name,
implementor_location: Option<SourceSpan>,
implements_interfaces: &IndexSet<ComponentName>,
) {
let interface_definitions = implements_interfaces
.iter()
.filter_map(|name| {
schema
.get_interface(name)
.map(|interface| (name, interface))
})
.collect::<Vec<_>>();
for interface_name in implements_interfaces {
if schema.get_interface(interface_name).is_some() {
continue;
}
let loc = interface_name.location();
diagnostics.push(
loc,
DiagnosticData::UndefinedDefinition {
name: interface_name.name.clone(),
},
);
}
let transitive_interfaces = interface_definitions.iter().flat_map(|&(name, interface)| {
interface
.implements_interfaces
.iter()
.map(|component| &component.name)
.zip(std::iter::repeat(name))
});
for (transitive_interface, via_interface) in transitive_interfaces {
if implements_interfaces.contains(transitive_interface) {
continue;
}
let transitive_loc = transitive_interface.location();
diagnostics.push(
implementor_location,
DiagnosticData::TransitiveImplementedInterfaces {
interface: implementor_name.clone(),
via_interface: via_interface.name.clone(),
missing_interface: transitive_interface.clone(),
transitive_interface_location: transitive_loc,
},
);
}
}