Skip to content

Commit 724eb1c

Browse files
author
Justin Anastos
authored
AP-682 Strip FragmentDefinitions in client:check when only… (#1454)
2 parents 15dcd87 + 09161d9 commit 724eb1c

4 files changed

Lines changed: 540 additions & 22 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
- `apollo-graphql`
2020
- <First `apollo-graphql` related entry goes here>
2121
- `apollo-language-server`
22-
- <First `apollo-language-server` related entry goes here>
22+
- Fix issue where fragment definitions only included in `@client` fields would not be stripped ((AP-682)(https://golinks.io/AP-682), [#1454](https://github.com/apollographql/apollo-tooling/pull/1454))
2323
- `apollo-tools`
2424
- <First `apollo-tools` related entry goes here>
2525
- `vscode-apollo`

packages/apollo-language-server/src/project/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ export class GraphQLClientProject extends GraphQLProject {
390390
for (const operationName in current) {
391391
const document = current[operationName];
392392

393-
let serviceOnly: DocumentNode = removeDirectiveAnnotatedFields(
393+
let serviceOnly = removeDirectiveAnnotatedFields(
394394
removeDirectives(document, clientOnlyDirectives as string[]),
395395
clientSchemaDirectives as string[]
396396
);

packages/apollo-language-server/src/utilities/__tests__/graphql.test.ts

Lines changed: 338 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import gql from "graphql-tag";
2-
import { print } from "graphql";
3-
import { withTypenameFieldAddedWhereNeeded } from "../graphql";
2+
import { parse, print } from "graphql";
3+
import {
4+
withTypenameFieldAddedWhereNeeded,
5+
removeDirectiveAnnotatedFields
6+
} from "../graphql";
47

58
describe("withTypenameFieldAddedWhereNeeded", () => {
69
it("properly adds __typename to each selectionSet", () => {
@@ -73,3 +76,336 @@ describe("withTypenameFieldAddedWhereNeeded", () => {
7376
`);
7477
});
7578
});
79+
80+
describe("removeDirectiveAnnotatedFields", () => {
81+
it("should remove fields with matching directives", () => {
82+
expect(
83+
print(
84+
removeDirectiveAnnotatedFields(
85+
parse(`query Query { fieldToKeep fieldToRemove @client }`),
86+
["client"]
87+
)
88+
)
89+
).toMatchInlineSnapshot(`
90+
"query Query {
91+
fieldToKeep
92+
}
93+
"
94+
`);
95+
});
96+
97+
it("trim selections sets that are client only", () => {
98+
expect(
99+
print(
100+
removeDirectiveAnnotatedFields(
101+
parse(`
102+
query Query {
103+
fieldToKeep
104+
fieldToRemove @client {
105+
childField
106+
}
107+
}
108+
`),
109+
["client"]
110+
)
111+
)
112+
).toMatchInlineSnapshot(`
113+
"query Query {
114+
fieldToKeep
115+
}
116+
"
117+
`);
118+
});
119+
120+
it("should remove fragments when a directive is used on a fragment spread", () => {
121+
expect(
122+
print(
123+
removeDirectiveAnnotatedFields(
124+
parse(`
125+
{
126+
me { name }
127+
...ClientFields @client
128+
}
129+
fragment ClientFields on Query {
130+
hello
131+
}
132+
`),
133+
["client"]
134+
)
135+
)
136+
).toMatchInlineSnapshot(`
137+
"{
138+
me {
139+
name
140+
}
141+
}
142+
"
143+
`);
144+
});
145+
146+
it("should remove fragments when client directive is used inline", () => {
147+
expect(
148+
print(
149+
removeDirectiveAnnotatedFields(
150+
parse(`
151+
{
152+
me { name }
153+
... on Query @client {
154+
hello
155+
}
156+
}
157+
`),
158+
["client"]
159+
)
160+
)
161+
).toMatchInlineSnapshot(`
162+
"{
163+
me {
164+
name
165+
}
166+
}
167+
"
168+
`);
169+
});
170+
171+
it("should remove fragments when the client directive is on the definition", () => {
172+
expect(
173+
print(
174+
removeDirectiveAnnotatedFields(
175+
parse(`
176+
fragment ClientObject on Query @client {
177+
hello
178+
}
179+
{
180+
me { name }
181+
... ClientObject
182+
}
183+
`),
184+
["client"]
185+
)
186+
)
187+
).toMatchInlineSnapshot(`
188+
"{
189+
me {
190+
name
191+
}
192+
}
193+
"
194+
`);
195+
});
196+
197+
it("should remove fragments that become unused when antecendant directives are removed", () => {
198+
expect(
199+
print(
200+
removeDirectiveAnnotatedFields(
201+
parse(`
202+
fragment ClientObjectFragment on ClientObject {
203+
string
204+
number
205+
}
206+
207+
fragment LaunchTile on Launch {
208+
__typename
209+
id
210+
isBooked
211+
rocket {
212+
id
213+
name
214+
}
215+
mission {
216+
name
217+
missionPatch
218+
}
219+
}
220+
221+
query LaunchDetails($launchId: ID!) {
222+
launch(id: $launchId) {
223+
isInCart @client
224+
clientObject @client {
225+
...ClientObjectFragment
226+
}
227+
site
228+
rocket {
229+
type
230+
}
231+
...LaunchTile
232+
}
233+
}
234+
`),
235+
["client"]
236+
)
237+
)
238+
).toMatchInlineSnapshot(`
239+
"fragment LaunchTile on Launch {
240+
__typename
241+
id
242+
isBooked
243+
rocket {
244+
id
245+
name
246+
}
247+
mission {
248+
name
249+
missionPatch
250+
}
251+
}
252+
253+
query LaunchDetails($launchId: ID!) {
254+
launch(id: $launchId) {
255+
site
256+
rocket {
257+
type
258+
}
259+
...LaunchTile
260+
}
261+
}
262+
"
263+
`);
264+
});
265+
266+
it("should recursively remove fragments that become unused when antecendant directives are removed", () => {
267+
expect(
268+
print(
269+
removeDirectiveAnnotatedFields(
270+
parse(`
271+
fragment One on Node {
272+
...Two
273+
user {
274+
friends {
275+
name
276+
...Two @client
277+
}
278+
}
279+
}
280+
fragment Two on Node {
281+
id
282+
}
283+
284+
query {
285+
me {
286+
...One
287+
}
288+
}
289+
`),
290+
["client"]
291+
)
292+
)
293+
).toMatchInlineSnapshot(`
294+
"fragment One on Node {
295+
...Two
296+
user {
297+
friends {
298+
name
299+
}
300+
}
301+
}
302+
303+
fragment Two on Node {
304+
id
305+
}
306+
307+
{
308+
me {
309+
...One
310+
}
311+
}
312+
"
313+
`);
314+
});
315+
316+
it("should remove fragment spreads from @client fragment definitions", () => {
317+
expect(
318+
print(
319+
removeDirectiveAnnotatedFields(
320+
parse(`
321+
fragment One on Node @client {
322+
...Two
323+
}
324+
325+
fragment Two on Node {
326+
id
327+
}
328+
329+
query {
330+
me {
331+
name
332+
...One
333+
}
334+
}
335+
`),
336+
["client"]
337+
)
338+
)
339+
).toMatchInlineSnapshot(`
340+
"{
341+
me {
342+
name
343+
}
344+
}
345+
"
346+
`);
347+
});
348+
349+
it("should remove all operations that have no selection set after fragments are removed", () => {
350+
expect(
351+
print(
352+
removeDirectiveAnnotatedFields(
353+
parse(`
354+
fragment One on Node @client {
355+
...Two
356+
}
357+
358+
fragment Two on Node {
359+
id
360+
}
361+
362+
{
363+
name
364+
me {
365+
...One
366+
}
367+
}
368+
`),
369+
["client"]
370+
)
371+
)
372+
).toMatchInlineSnapshot(`
373+
"{
374+
name
375+
}
376+
"
377+
`);
378+
});
379+
380+
it("should not remove fragment definitions that weren't removed by `removeDirectiveAnnotatedFields`", () => {
381+
expect(
382+
print(
383+
removeDirectiveAnnotatedFields(
384+
parse(`
385+
fragment One on Node {
386+
id
387+
}
388+
389+
{
390+
me {
391+
name
392+
}
393+
}
394+
`),
395+
["client"]
396+
)
397+
)
398+
).toMatchInlineSnapshot(`
399+
"fragment One on Node {
400+
id
401+
}
402+
403+
{
404+
me {
405+
name
406+
}
407+
}
408+
"
409+
`);
410+
});
411+
});

0 commit comments

Comments
 (0)