in compiler/crates/relay-lsp/src/hover/with_resolution_path.rs [600:712]
fn get_scalar_or_linked_field_hover_content(
field_name: &Identifier,
field_selection_path: &SelectionPath<'_>,
schema: &SDLSchema,
schema_name: StringKey,
schema_documentation: &impl SchemaDocumentation,
content_consumer_type: ContentConsumerType,
) -> Option<Vec<MarkedString>> {
let parent_types = field_selection_path.parent.find_type_path(schema);
let parent_type = parent_types.last()?;
let mut type_path = parent_types
.iter()
.map(|parent_type| schema.get_type_name(*parent_type).lookup())
.collect::<Vec<_>>();
let parent_type_name = schema.get_type_name(*parent_type).lookup();
let field = schema
.named_field(*parent_type, field_name.value)
.map(|id| schema.field(id))?;
let is_resolver = field
.directives
.named(*RELAY_RESOLVER_DIRECTIVE_NAME)
.is_some();
let rendered_type_string = schema.get_type_string(&field.type_);
let field_type_name = schema.get_type_name(field.type_.inner()).lookup();
let mut hover_contents: Vec<MarkedString> = vec![MarkedString::String(format!(
"Field: **{}**",
field.name.item
))];
if let Some(field_description) =
schema_documentation.get_field_description(parent_type_name, field.name.item.lookup())
{
hover_contents.push(MarkedString::String(field_description.to_string()));
}
type_path.push(field_type_name);
// Relay Resolvers return the return type of their resolver function. This can be any JavaScript value
// so it's not correctly modeled in our schema types.
if !is_resolver {
hover_contents.push(MarkedString::String(format!(
"Type: **{}**",
content_consumer_type.render_text_with_params(
&rendered_type_string,
&GraphQLSchemaExplorerParams {
path: type_path,
schema_name: schema_name.lookup(),
filter: None,
}
)
)));
}
if let Some(type_description) = schema_documentation.get_type_description(field_type_name) {
hover_contents.push(MarkedString::String(type_description.to_string()));
}
if !field.arguments.is_empty() {
hover_contents.push(MarkedString::String(
"This field accepts these arguments".to_string(),
));
for arg in field.arguments.iter() {
let arg_type_name = schema.get_type_name(arg.type_.inner()).lookup();
hover_contents.push(MarkedString::from_markdown(format!(
"{}: **{}**{}\n\n{}",
arg.name,
content_consumer_type.render_text_with_params(
&schema.get_type_string(&arg.type_),
&GraphQLSchemaExplorerParams {
path: vec![field_type_name, arg_type_name],
schema_name: schema_name.lookup(),
filter: None,
}
),
if let Some(default_value) = &arg.default_value {
format!(" = {}", default_value)
} else {
"".to_string()
},
if let Some(description) = schema_documentation.get_field_argument_description(
parent_type_name,
field.name.item.lookup(),
arg.name.lookup(),
) {
description.to_string()
} else {
"".to_string()
}
)));
}
}
if is_resolver {
let msg = "**Relay Resolver**: This field is backed by a Relay Resolver, and is therefore only avaliable in Relay code. [Learn More](https://relay.dev/docs/next/guides/relay-resolvers/).";
hover_contents.push(MarkedString::String(msg.to_string()))
} else if field.is_extension {
let msg = match content_consumer_type {
ContentConsumerType::Relay => {
"**Client Schema Extension**: This field was declared as a Relay Client Schema Extension, and is therefore only avalaible in Relay code. [Learn More](https://relay.dev/docs/guided-tour/updating-data/client-only-data/#client-only-data-client-schema-extensions)."
}
ContentConsumerType::GraphQL => {
"**Client Schema Extension**: This field was declared as a GraphQL client schema extension explicitly among [these](https://fburl.com/code/9qg1gghd) files etc."
}
};
hover_contents.push(MarkedString::String(msg.to_string()))
}
Some(hover_contents)
}