Skip to content

Commit

Permalink
feat(biome_graphql_parser): parse union type definition
Browse files Browse the repository at this point in the history
  • Loading branch information
vohoanglong0107 committed May 5, 2024
1 parent 9c4be6b commit e0160b4
Show file tree
Hide file tree
Showing 6 changed files with 754 additions and 0 deletions.
5 changes: 5 additions & 0 deletions crates/biome_graphql_parser/src/parser/definitions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod object;
mod operation;
mod scalar;
mod schema;
mod union;

use crate::parser::{parse_error::expected_any_definition, GraphqlParser};
use biome_graphql_syntax::GraphqlSyntaxKind::{self, *};
Expand All @@ -20,6 +21,7 @@ use self::{
operation::{is_at_operation, parse_operation_definition},
scalar::{is_at_scalar_type_definition, parse_scalar_type_definition},
schema::{is_at_schema_definition, parse_schema_definition},
union::{is_at_union_type_definition, parse_union_type_definition},
};
pub(crate) use operation::is_at_selection_set_end;

Expand Down Expand Up @@ -76,6 +78,8 @@ fn parse_definition(p: &mut GraphqlParser) -> ParsedSyntax {
parse_object_type_definition(p)
} else if is_at_interface_type_definition(p) {
parse_interface_type_definition(p)
} else if is_at_union_type_definition(p) {
parse_union_type_definition(p)
} else {
Absent
}
Expand All @@ -90,4 +94,5 @@ fn is_at_definition(p: &mut GraphqlParser<'_>) -> bool {
|| is_at_scalar_type_definition(p)
|| is_at_object_type_definition(p)
|| is_at_interface_type_definition(p)
|| is_at_union_type_definition(p)
}
139 changes: 139 additions & 0 deletions crates/biome_graphql_parser/src/parser/definitions/union.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use crate::parser::{
directive::DirectiveList,
is_at_name, parse_description,
parse_error::{expected_name, expected_named_type},
parse_name,
r#type::parse_named_type,
value::is_at_string,
GraphqlParser,
};
use biome_graphql_syntax::{
GraphqlSyntaxKind::{self, *},
T,
};
use biome_parser::{
parse_lists::{ParseNodeList, ParseSeparatedList},
parse_recovery::ParseRecovery,
parsed_syntax::ParsedSyntax,
prelude::ParsedSyntax::*,
token_source::TokenSource,
Parser,
};

use super::is_at_definition;

#[inline]
pub(crate) fn parse_union_type_definition(p: &mut GraphqlParser) -> ParsedSyntax {
if !is_at_union_type_definition(p) {
return Absent;
}
let m = p.start();

// description is optional
parse_description(p).ok();

p.bump(T![union]);

parse_name(p).or_add_diagnostic(p, expected_name);

DirectiveList.parse_list(p);

// union member types are optional
parse_union_member_types(p).ok();

Present(m.complete(p, GRAPHQL_UNION_TYPE_DEFINITION))
}

#[inline]
fn parse_union_member_types(p: &mut GraphqlParser) -> ParsedSyntax {
if !is_at_union_member_types(p) {
return Absent;
}
let m = p.start();
p.expect(T![=]);

if p.at(T![|]) {
p.bump(T![|]);
}

let position = p.source().position();
UnionMemberTypeList.parse_list(p);

// has not progressed, meaning no union member types were parsed
if position == p.source().position() {
p.error(expected_named_type(p, p.cur_range()));
}
Present(m.complete(p, GRAPHQL_UNION_MEMBER_TYPES))
}

#[derive(Default)]
struct UnionMemberTypeList;

impl ParseSeparatedList for UnionMemberTypeList {
type Kind = GraphqlSyntaxKind;
type Parser<'source> = GraphqlParser<'source>;

const LIST_KIND: Self::Kind = GRAPHQL_UNION_MEMBER_TYPE_LIST;

fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax {
parse_named_type(p)
}

fn is_at_list_end(&self, p: &mut Self::Parser<'_>) -> bool {
is_at_union_member_types_end(p)
}

fn recover(
&mut self,
p: &mut Self::Parser<'_>,
parsed_element: ParsedSyntax,
) -> biome_parser::parse_recovery::RecoveryResult {
parsed_element.or_recover(p, &UnionMemberListParseRecovery, expected_named_type)
}

fn separating_element_kind(&mut self) -> Self::Kind {
T![|]
}

fn allow_trailing_separating_element(&self) -> bool {
false
}
}

struct UnionMemberListParseRecovery;

impl ParseRecovery for UnionMemberListParseRecovery {
type Kind = GraphqlSyntaxKind;
type Parser<'source> = GraphqlParser<'source>;
const RECOVERED_KIND: Self::Kind = GRAPHQL_BOGUS;

fn is_at_recovered(&self, p: &mut Self::Parser<'_>) -> bool {
p.at(T![|])
// After a union definition is a new type definition so it's safe to
// assume any name we see before a new type definition is a union
// member type
|| is_at_name(p)
|| is_at_union_member_types_end(p)
}
}

#[inline]
pub(crate) fn is_at_union_type_definition(p: &mut GraphqlParser<'_>) -> bool {
p.at(T![union]) || (is_at_string(p) && p.nth_at(1, T![union]))
}

#[inline]
fn is_at_union_member_types(p: &mut GraphqlParser<'_>) -> bool {
p.at(T![=])
// missing =
|| p.at(T![|])
// missing both = and |. After a union definition is a new type definition
// so it's safe to assume any name we see before a new type definition is
// a union member type
|| is_at_name(p)
}

#[inline]
fn is_at_union_member_types_end(p: &mut GraphqlParser<'_>) -> bool {
is_at_definition(p)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
union SearchResult = Photo |

union SearchResult
| Photo
| Person


union SearchResult |

union SearchResult =

union SearchResult = |

union SearchResult @ =
Loading

0 comments on commit e0160b4

Please sign in to comment.