@@ -8,9 +8,78 @@ export function gql(
88 chunks : TemplateStringsArray ,
99 ...values : unknown [ ]
1010) : string {
11- return chunks . reduce (
11+ const source = chunks . reduce (
1212 ( source , chunk , index ) =>
1313 `${ source } ${ chunk } ${ index in values ? String ( values [ index ] ) : "" } ` ,
1414 "" ,
1515 ) ;
16+
17+ return dedupeFragmentDefinitions ( source ) ;
18+ }
19+
20+ function dedupeFragmentDefinitions ( source : string ) : string {
21+ const seen = new Set < string > ( ) ;
22+ const fragmentPattern =
23+ / \b f r a g m e n t \s + ( [ _ A - Z a - z ] [ _ 0 - 9 A - Z a - z ] * ) \s + o n \s + [ _ A - Z a - z ] [ _ 0 - 9 A - Z a - z ] * / g;
24+
25+ let result = "" ;
26+ let cursor = 0 ;
27+ let match = fragmentPattern . exec ( source ) ;
28+
29+ while ( match ) {
30+ const name = match [ 1 ] ;
31+ if ( ! name ) {
32+ match = fragmentPattern . exec ( source ) ;
33+ continue ;
34+ }
35+
36+ const bodyStart = source . indexOf ( "{" , fragmentPattern . lastIndex ) ;
37+ if ( bodyStart === - 1 ) {
38+ match = fragmentPattern . exec ( source ) ;
39+ continue ;
40+ }
41+
42+ const bodyEnd = findMatchingBrace ( source , bodyStart ) ;
43+ if ( bodyEnd === - 1 ) {
44+ match = fragmentPattern . exec ( source ) ;
45+ continue ;
46+ }
47+
48+ const fragmentStart = match . index ;
49+ const fragmentEnd = consumeTrailingWhitespace ( source , bodyEnd + 1 ) ;
50+
51+ if ( ! seen . has ( name ) ) {
52+ seen . add ( name ) ;
53+ result += source . slice ( cursor , fragmentEnd ) ;
54+ } else {
55+ result += source . slice ( cursor , fragmentStart ) ;
56+ }
57+
58+ cursor = fragmentEnd ;
59+ fragmentPattern . lastIndex = fragmentEnd ;
60+ match = fragmentPattern . exec ( source ) ;
61+ }
62+
63+ return result + source . slice ( cursor ) ;
64+ }
65+
66+ function findMatchingBrace ( source : string , openBraceIndex : number ) : number {
67+ let depth = 0 ;
68+
69+ for ( let index = openBraceIndex ; index < source . length ; index ++ ) {
70+ const char = source [ index ] ;
71+ if ( char === "{" ) depth ++ ;
72+ if ( char === "}" ) depth -- ;
73+ if ( depth === 0 ) return index ;
74+ }
75+
76+ return - 1 ;
77+ }
78+
79+ function consumeTrailingWhitespace ( source : string , index : number ) : number {
80+ let next = index ;
81+ while ( next < source . length && / \s / . test ( source [ next ] ?? "" ) ) {
82+ next ++ ;
83+ }
84+ return next ;
1685}
0 commit comments