11import { Plugin } from '@envelop/types' ;
2- import { Parser , ParseOptions } from 'graphql/language/parser' ;
3- import { Lexer } from 'graphql/language/lexer' ;
2+ import { ParseOptions } from 'graphql/language/parser' ;
3+ import { Source , DocumentNode } from 'graphql' ;
4+ import { FragmentArgumentCompatibleParser } from './extended-parser' ;
5+ import { applySelectionSetFragmentArguments } from './utils' ;
46
5- import {
6- TokenKind ,
7- Kind ,
8- Source ,
9- DocumentNode ,
10- visit ,
11- FragmentDefinitionNode ,
12- InlineFragmentNode ,
13- ArgumentNode ,
14- TokenKindEnum ,
15- Token ,
16- } from 'graphql' ;
7+ export function parseWithFragmentArguments ( source : string | Source , options ?: ParseOptions ) : DocumentNode {
8+ const parser = new FragmentArgumentCompatibleParser ( source , options ) ;
179
18- declare module 'graphql/language/parser' {
19- export class Parser {
20- constructor ( source : string | Source , options ?: ParseOptions ) ;
21- _lexer : Lexer ;
22- expectOptionalKeyword ( word : string ) : boolean ;
23- expectToken ( token : TokenKindEnum ) : void ;
24- peek ( token : TokenKindEnum ) : boolean ;
25- parseFragmentName ( ) : string ;
26- parseArguments ( flag : boolean ) : any ;
27- parseDirectives ( flag : boolean ) : any ;
28- loc ( start : Token ) : any ;
29- parseNamedType ( ) : any ;
30- parseSelectionSet ( ) : any ;
31- expectKeyword ( keyword : string ) : void ;
32- parseVariableDefinitions ( ) : void ;
33- parseDocument ( ) : DocumentNode ;
34- }
35- }
36-
37- class FragmentArgumentCompatible extends Parser {
38- parseFragment ( ) {
39- const start = this . _lexer . token ;
40- this . expectToken ( TokenKind . SPREAD ) ;
41- const hasTypeCondition = this . expectOptionalKeyword ( 'on' ) ;
42- if ( ! hasTypeCondition && this . peek ( TokenKind . NAME ) ) {
43- const name = this . parseFragmentName ( ) ;
44- if ( this . peek ( TokenKind . PAREN_L ) ) {
45- return {
46- kind : Kind . FRAGMENT_SPREAD ,
47- name,
48- arguments : this . parseArguments ( false ) ,
49- directives : this . parseDirectives ( false ) ,
50- loc : this . loc ( start ) ,
51- } ;
52- }
53- return {
54- kind : Kind . FRAGMENT_SPREAD ,
55- name : this . parseFragmentName ( ) ,
56- directives : this . parseDirectives ( false ) ,
57- loc : this . loc ( start ) ,
58- } ;
59- }
60- return {
61- kind : Kind . INLINE_FRAGMENT ,
62- typeCondition : hasTypeCondition ? this . parseNamedType ( ) : undefined ,
63- directives : this . parseDirectives ( false ) ,
64- selectionSet : this . parseSelectionSet ( ) ,
65- loc : this . loc ( start ) ,
66- } ;
67- }
68-
69- parseFragmentDefinition ( ) {
70- const start = this . _lexer . token ;
71- this . expectKeyword ( 'fragment' ) ;
72- const name = this . parseFragmentName ( ) ;
73- if ( this . peek ( TokenKind . PAREN_L ) ) {
74- return {
75- kind : Kind . FRAGMENT_DEFINITION ,
76- name,
77- variableDefinitions : this . parseVariableDefinitions ( ) ,
78- typeCondition : ( this . expectKeyword ( 'on' ) , this . parseNamedType ( ) ) ,
79- directives : this . parseDirectives ( false ) ,
80- selectionSet : this . parseSelectionSet ( ) ,
81- loc : this . loc ( start ) ,
82- } ;
83- }
84-
85- return {
86- kind : Kind . FRAGMENT_DEFINITION ,
87- name,
88- typeCondition : ( this . expectKeyword ( 'on' ) , this . parseNamedType ( ) ) ,
89- directives : this . parseDirectives ( false ) ,
90- selectionSet : this . parseSelectionSet ( ) ,
91- loc : this . loc ( start ) ,
92- } ;
93- }
94- }
95-
96- function pimpedParse ( source : string | Source , options ?: ParseOptions ) : DocumentNode {
97- const parser = new FragmentArgumentCompatible ( source , options ) ;
9810 return parser . parseDocument ( ) ;
9911}
10012
10113export const useFragmentArguments = ( ) : Plugin => {
10214 return {
10315 onParse ( { setParseFn } ) {
104- setParseFn ( pimpedParse ) ;
16+ setParseFn ( parseWithFragmentArguments ) ;
10517
10618 return ( { result, replaceParseResult } ) => {
10719 if ( result && 'kind' in result ) {
@@ -111,53 +23,3 @@ export const useFragmentArguments = (): Plugin => {
11123 } ,
11224 } ;
11325} ;
114-
115- function applySelectionSetFragmentArguments ( document : DocumentNode ) : DocumentNode | Error {
116- const fragmentList = new Map < string , FragmentDefinitionNode > ( ) ;
117- for ( const def of document . definitions ) {
118- if ( def . kind !== 'FragmentDefinition' ) {
119- continue ;
120- }
121- fragmentList . set ( def . name . value , def ) ;
122- }
123-
124- return visit ( document , {
125- FragmentSpread ( fragmentNode ) {
126- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
127- // @ts -ignore
128- if ( fragmentNode . arguments != null && fragmentNode . arguments . length ) {
129- const fragmentDef = fragmentList . get ( fragmentNode . name . value ) ;
130- if ( ! fragmentDef ) {
131- return ;
132- }
133-
134- const fragmentArguments = new Map < string , ArgumentNode > ( ) ;
135- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
136- // @ts -ignore
137- for ( const arg of fragmentNode . arguments ) {
138- fragmentArguments . set ( arg . name . value , arg ) ;
139- }
140-
141- const selectionSet = visit ( fragmentDef . selectionSet , {
142- Variable ( variableNode ) {
143- const fragArg = fragmentArguments . get ( variableNode . name . value ) ;
144- if ( fragArg ) {
145- return fragArg . value ;
146- }
147-
148- return variableNode ;
149- } ,
150- } ) ;
151-
152- const inlineFragment : InlineFragmentNode = {
153- kind : 'InlineFragment' ,
154- typeCondition : fragmentDef . typeCondition ,
155- selectionSet,
156- } ;
157-
158- return inlineFragment ;
159- }
160- return fragmentNode ;
161- } ,
162- } ) ;
163- }
0 commit comments