11import { getValueWithoutLoc } from '@/GqlParser/valueNode' ;
2- import { OperationType , ParserField } from '@/Models' ;
2+ import { OperationType , ParserField , TypeDefinition } from '@/Models' ;
33import { GqlParserTree , VariableDefinitionWithoutLoc } from '@/Models/GqlParserTree' ;
44import { Parser } from '@/Parser' ;
55import { TypeResolver } from '@/Parser/typeResolver' ;
6- import { compileType } from '@/shared' ;
6+ import { compileType , getTypeName } from '@/shared' ;
77import {
88 DefinitionNode ,
99 parse ,
@@ -13,10 +13,14 @@ import {
1313 DirectiveNode ,
1414 FieldNode ,
1515 VariableDefinitionNode ,
16+ FragmentDefinitionNode ,
17+ FragmentSpreadNode ,
18+ InlineFragmentNode ,
1619} from 'graphql' ;
17- export const GqlParser = ( gql : string , schema : string ) => {
20+ export const parseGql = ( gql : string , schema : string ) => {
1821 const { definitions } = parse ( schema + '\n' + gql ) ;
1922 const ops = definitions . filter ( onlyOperations ) ;
23+ const frags = definitions . filter ( onlyFragments ) ;
2024 const { nodes } = Parser . parse ( schema ) ;
2125
2226 const composeDefinition = ( d : OperationDefinitionNode ) : GqlParserTree => {
@@ -42,7 +46,21 @@ export const GqlParser = (gql: string, schema: string) => {
4246 variableDefinitions : d . variableDefinitions . map ( ( vd ) => composeVariableDefinition ( vd ) ) ,
4347 }
4448 : { } ) ,
45- children : d . selectionSet . selections . filter ( onlyFieldNodes ) . map ( ( s ) => composeSelectionNode ( s , node ) ) ,
49+ children : d . selectionSet . selections . map ( ( s ) => composeSelectionNode ( s , node ) ) ,
50+ } ;
51+ } ;
52+
53+ const composeFragment = ( f : FragmentDefinitionNode ) : GqlParserTree => {
54+ const node = nodes . find ( ( n ) => n . name == f . typeCondition . name . value ) ;
55+ if ( ! node ) {
56+ throw new Error ( `Type ${ f . typeCondition . name . value } does not exist in schema` ) ;
57+ }
58+ return {
59+ node,
60+ fragment : true ,
61+ name : f . name . value ,
62+ ...( f . directives ?. length ? { directives : f . directives . map ( ( a ) => composeDirectiveNode ( a , node ) ) } : { } ) ,
63+ children : f . selectionSet . selections . map ( ( s ) => composeSelectionNode ( s , node ) ) ,
4664 } ;
4765 } ;
4866
@@ -74,29 +92,66 @@ export const GqlParser = (gql: string, schema: string) => {
7492 return {
7593 node,
7694 name : a . name . value ,
77- arguments : a . arguments ?. map ( ( a ) => composeArgumentNode ( a , node ) ) ,
95+ ... ( a . arguments ?. length ? { arguments : a . arguments ?. map ( ( ar ) => composeArgumentNode ( ar , node ) ) } : { } ) ,
7896 } ;
7997 } ;
8098
81- const composeSelectionNode = ( s : FieldNode , parentNode : ParserField ) : GqlParserTree => {
99+ const composeFragmentSpread = ( f : FragmentSpreadNode , node : ParserField ) : GqlParserTree => {
100+ return {
101+ node,
102+ name : f . name . value ,
103+ ...( f . directives ?. length ? { directives : f . directives ?. map ( ( a ) => composeDirectiveNode ( a , node ) ) } : { } ) ,
104+ fragmentSpread : true ,
105+ } ;
106+ } ;
107+ const composeInlineFragment = ( f : InlineFragmentNode , node : ParserField ) : GqlParserTree => {
108+ const chosenNode = nodes . find ( ( n ) => n . name === f . typeCondition ?. name . value ) ;
109+ const rightNode = chosenNode || node ;
110+ return {
111+ node : rightNode ,
112+ name : rightNode . name ,
113+ ...( f . directives ?. length ? { directives : f . directives ?. map ( ( a ) => composeDirectiveNode ( a , rightNode ) ) } : { } ) ,
114+ inlineFragment : true ,
115+ children : f . selectionSet . selections . map ( ( s ) => composeSelectionNode ( s , rightNode ) ) ,
116+ } ;
117+ } ;
118+
119+ const composeSelectionNode = ( s : SelectionNode , node : ParserField ) : GqlParserTree => {
120+ if ( s . kind === 'Field' ) return composeFieldNode ( s , node ) ;
121+ if ( s . kind === 'FragmentSpread' ) return composeFragmentSpread ( s , node ) ;
122+ return composeInlineFragment ( s , node ) ;
123+ } ;
124+
125+ const composeFieldNode = ( s : FieldNode , parentNode : ParserField ) : GqlParserTree => {
82126 const fieldNode = parentNode . args . find ( ( a ) => a . name === s . name . value ) ;
83127 if ( ! fieldNode ) {
84- throw new Error ( ' Field does not exist in schema' ) ;
128+ throw new Error ( ` Field " ${ s . name . value } " does not exist in " ${ parentNode . name } " node` ) ;
85129 }
130+ const passParentDown = getTypeName ( fieldNode . type . fieldType ) ;
131+ const isParentObjectNode = nodes . find (
132+ ( n ) =>
133+ n . name === passParentDown &&
134+ ( n . data . type === TypeDefinition . ObjectTypeDefinition ||
135+ n . data . type === TypeDefinition . UnionTypeDefinition ||
136+ n . data . type === TypeDefinition . InterfaceTypeDefinition ) ,
137+ ) ;
138+
86139 return {
87140 node : fieldNode ,
88141 name : s . name . value ,
89- arguments : s . arguments ?. map ( ( a ) => composeArgumentNode ( a , fieldNode ) ) ,
90- directives : s . directives ?. map ( ( a ) => composeDirectiveNode ( a , fieldNode ) ) ,
91- children : s . selectionSet ?. selections . filter ( onlyFieldNodes ) . map ( ( a ) => composeSelectionNode ( a , fieldNode ) ) ,
142+ ...( s . arguments ?. length ? { arguments : s . arguments ?. map ( ( a ) => composeArgumentNode ( a , fieldNode ) ) } : { } ) ,
143+ ...( s . directives ?. length ? { directives : s . directives ?. map ( ( a ) => composeDirectiveNode ( a , fieldNode ) ) } : { } ) ,
144+ ...( s . selectionSet ?. selections . length
145+ ? { children : s . selectionSet . selections . map ( ( s ) => composeSelectionNode ( s , isParentObjectNode || fieldNode ) ) }
146+ : { } ) ,
92147 } as GqlParserTree ;
93148 } ;
94- return ops . map ( ( o ) => composeDefinition ( o ) ) ;
149+ return [ ... frags . map ( ( f ) => composeFragment ( f ) ) , ... ops . map ( ( o ) => composeDefinition ( o ) ) ] ;
95150} ;
96151
97152const onlyOperations = ( definition : DefinitionNode ) : definition is OperationDefinitionNode => {
98153 return definition . kind === 'OperationDefinition' ;
99154} ;
100- const onlyFieldNodes = ( definition : SelectionNode ) : definition is FieldNode => {
101- return definition . kind === 'Field ' ;
155+ const onlyFragments = ( definition : DefinitionNode ) : definition is FragmentDefinitionNode => {
156+ return definition . kind === 'FragmentDefinition ' ;
102157} ;
0 commit comments