apollo-language-server 0.7.0

A GraphQL language server with first-class support for Apollo Federation
Documentation
pub mod connect;
pub mod federation;
pub mod link;
pub mod tag;

use apollo_compiler::{
    ast::{
        DirectiveDefinition, EnumTypeDefinition, InputObjectTypeDefinition, ScalarTypeDefinition,
    },
    parser::Parser,
    Node,
};
use connect::{CONNECT_SPECS_BY_VERSION, CONNECT_SPEC_NAME};
use federation::{FEDERATION_SPECS_BY_VERSION, FEDERATION_SPEC_NAME};
use link::{LINK_SPECS_BY_VERSION, LINK_SPEC_NAME};
use once_cell::sync::Lazy;
use std::{
    collections::HashMap,
    fmt::{Display, Formatter},
};
use tag::{TAG_SPECS_BY_VERSION, TAG_SPEC_NAME};

#[derive(Debug, Clone)]
pub struct SpecDirective {
    pub node: Node<DirectiveDefinition>,
}

impl SpecDirective {
    pub fn new(definition_text: &str, description: &str) -> SpecDirective {
        let ast = Parser::new()
            .parse_ast(
                format!("\"\"\"\n{}\n\"\"\"\n{}", description, definition_text),
                "directive.graphql",
            )
            .unwrap();
        let node = ast.definitions[0]
            .as_directive_definition()
            .unwrap()
            .clone();

        SpecDirective { node }
    }
}

impl Display for SpecDirective {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        self.node.fmt(f)
    }
}

#[derive(Debug, Clone)]
pub struct SpecType<T> {
    pub node: Node<T>,
}

impl SpecType<EnumTypeDefinition> {
    pub fn new(definition_text: &str) -> SpecType<EnumTypeDefinition> {
        let ast = Parser::new()
            .parse_ast(definition_text, "type.graphql")
            .unwrap();
        let node = ast.definitions[0]
            .as_enum_type_definition()
            .unwrap()
            .clone();

        SpecType { node }
    }
}

impl SpecType<InputObjectTypeDefinition> {
    pub fn new(definition_text: &str) -> SpecType<InputObjectTypeDefinition> {
        let ast = Parser::new()
            .parse_ast(definition_text, "input_type.graphql")
            .unwrap();
        let node = ast.definitions[0]
            .as_input_object_type_definition()
            .unwrap()
            .clone();

        SpecType { node }
    }
}

impl SpecType<ScalarTypeDefinition> {
    pub fn new(name: &str) -> SpecType<ScalarTypeDefinition> {
        let ast = Parser::new()
            .parse_ast(format!("scalar {}", name), "scalar.graphql")
            .unwrap();
        let node = ast.definitions[0]
            .as_scalar_type_definition()
            .unwrap()
            .clone();

        SpecType { node }
    }
}

impl<T: Display> Display for SpecType<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        self.node.fmt(f)
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub enum SpecStatus {
    Deprecated,
    Experimental,
    Supported,
    Latest,
}

type SpecTypeMap<T> = HashMap<String, T>;

#[derive(Debug, Clone)]
pub struct Spec {
    pub scalars: SpecTypeMap<SpecType<ScalarTypeDefinition>>,
    pub input_types: SpecTypeMap<SpecType<InputObjectTypeDefinition>>,
    pub directives: SpecTypeMap<SpecDirective>,
    pub enums: SpecTypeMap<SpecType<EnumTypeDefinition>>,
    pub status: SpecStatus,
}

pub type SpecsByVersion = HashMap<String, Spec>;
pub type SpecVersionsByName = HashMap<String, SpecsByVersion>;

pub static KNOWN_SPECS: Lazy<SpecVersionsByName> = Lazy::new(|| {
    HashMap::from([
        (LINK_SPEC_NAME.to_string(), LINK_SPECS_BY_VERSION.clone()),
        (
            FEDERATION_SPEC_NAME.to_string(),
            FEDERATION_SPECS_BY_VERSION.clone(),
        ),
        (TAG_SPEC_NAME.to_string(), TAG_SPECS_BY_VERSION.clone()),
        (
            CONNECT_SPEC_NAME.to_string(),
            CONNECT_SPECS_BY_VERSION.clone(),
        ),
    ])
});