fn get_scalar_or_linked_field_hover_content()

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)
}