Skip to content

Commit 737d418

Browse files
Chnapyacao
andauthored
feat: add gql call expressions support (#2509)
Add ```gql(``)```, ```graphql(``)``` call expressions support for highlighting & language support - adds highlighting to grammar - create simper unit tests for just `findGraphQLTags` - removes some complex and seemingly unused legacy relay-related behaviour from `findGraphQLTags`. If you have any cases where graphql language support disappears with a nested graphql template tag/etc that worked before this, please let us know! Co-authored-by: Rikki Schulte <[email protected]>
1 parent 74aac2c commit 737d418

File tree

7 files changed

+307
-97
lines changed

7 files changed

+307
-97
lines changed

.changeset/three-rice-matter.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'vscode-graphql': patch
3+
'graphql-language-service-server': patch
4+
'graphql-language-service-cli': patch
5+
---
6+
7+
Add ```gql(``)```, ```graphql(``)``` call expressions support for highlighting & language

custom-words.txt

+1
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,4 @@ runtimes
233233
typeahead
234234
typeaheads
235235
unparsable
236+
randomthing

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"build:packages": "yarn tsc",
4545
"build:watch": "yarn tsc --watch",
4646
"watch": "yarn build:watch",
47-
"watch-vscode": "concurrently --raw 'yarn tsc --watch' 'yarn workspace vscode-graphql run compile --watch'",
47+
"watch-vscode": "concurrently --raw \"yarn tsc --watch\" \"yarn workspace vscode-graphql run compile --watch\"",
4848
"check": "yarn tsc --dry",
4949
"cypress-open": "yarn workspace graphiql cypress-open",
5050
"dev-graphiql": "yarn workspace graphiql dev",

packages/graphql-language-service-server/src/__tests__/MessageProcessor-test.ts

+53
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,36 @@ query Test {
563563
`);
564564
});
565565

566+
it('parseDocument finds queries in call expressions with template literals', async () => {
567+
const text = `
568+
// @flow
569+
import {gql} from 'react-apollo';
570+
import type {B} from 'B';
571+
import A from './A';
572+
573+
const QUERY = gql(\`
574+
query Test {
575+
test {
576+
value
577+
...FragmentsComment
578+
}
579+
}
580+
\${A.fragments.test}
581+
\`);
582+
583+
export function Example(arg: string) {}`;
584+
585+
const contents = parseDocument(text, 'test.js');
586+
expect(contents[0].query).toEqual(`
587+
query Test {
588+
test {
589+
value
590+
...FragmentsComment
591+
}
592+
}
593+
`);
594+
});
595+
566596
it('parseDocument finds queries in #graphql-annotated templates', async () => {
567597
const text = `
568598
import {gql} from 'react-apollo';
@@ -638,6 +668,29 @@ query Test {
638668
\${A.fragments.test}
639669
\`
640670
671+
export function Example(arg: string) {}`;
672+
673+
const contents = parseDocument(text, 'test.js');
674+
expect(contents.length).toEqual(0);
675+
});
676+
677+
it('parseDocument ignores non gql call expressions with template literals', async () => {
678+
const text = `
679+
// @flow
680+
import randomthing from 'package';
681+
import type {B} from 'B';
682+
import A from './A';
683+
684+
const QUERY = randomthing(\`
685+
query Test {
686+
test {
687+
value
688+
...FragmentsComment
689+
}
690+
}
691+
\${A.fragments.test}
692+
\`);
693+
641694
export function Example(arg: string) {}`;
642695

643696
const contents = parseDocument(text, 'test.js');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/**
2+
* Copyright (c) 2022 GraphQL Contributors
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*
8+
*/
9+
import { tmpdir } from 'os';
10+
11+
import { findGraphQLTags as baseFindGraphQLTags } from '../findGraphQLTags';
12+
13+
jest.mock('../Logger');
14+
15+
import { Logger } from '../Logger';
16+
17+
describe('findGraphQLTags', () => {
18+
const logger = new Logger(tmpdir());
19+
const findGraphQLTags = (text: string, ext: string) =>
20+
baseFindGraphQLTags(text, ext, '', logger);
21+
22+
it('finds queries in tagged templates', async () => {
23+
const text = `
24+
// @flow
25+
import {gql} from 'react-apollo';
26+
import type {B} from 'B';
27+
import A from './A';
28+
29+
const QUERY = gql\`
30+
query Test {
31+
test {
32+
value
33+
...FragmentsComment
34+
}
35+
}
36+
\${A.fragments.test}
37+
\`
38+
39+
export function Example(arg: string) {}`;
40+
41+
const contents = findGraphQLTags(text, '.js');
42+
expect(contents[0].template).toEqual(`
43+
query Test {
44+
test {
45+
value
46+
...FragmentsComment
47+
}
48+
}
49+
`);
50+
});
51+
52+
it('finds queries in call expressions with template literals', async () => {
53+
const text = `
54+
// @flow
55+
import {gql} from 'react-apollo';
56+
import type {B} from 'B';
57+
import A from './A';
58+
59+
const QUERY = gql(\`
60+
query Test {
61+
test {
62+
value
63+
...FragmentsComment
64+
}
65+
}
66+
\${A.fragments.test}
67+
\`);
68+
69+
export function Example(arg: string) {}`;
70+
71+
const contents = findGraphQLTags(text, '.js');
72+
expect(contents[0].template).toEqual(`
73+
query Test {
74+
test {
75+
value
76+
...FragmentsComment
77+
}
78+
}
79+
`);
80+
});
81+
82+
it('finds queries in #graphql-annotated templates', async () => {
83+
const text = `
84+
import {gql} from 'react-apollo';
85+
import {B} from 'B';
86+
import A from './A';
87+
88+
const QUERY: string = \`#graphql
89+
query Test {
90+
test {
91+
value
92+
...FragmentsComment
93+
}
94+
}
95+
\${A.fragments.test}
96+
\`
97+
98+
export function Example(arg: string) {}`;
99+
100+
const contents = findGraphQLTags(text, '.ts');
101+
expect(contents[0].template).toEqual(`#graphql
102+
query Test {
103+
test {
104+
value
105+
...FragmentsComment
106+
}
107+
}
108+
`);
109+
});
110+
111+
it('finds queries in /* GraphQL */ prefixed templates', async () => {
112+
const text = `
113+
import {gql} from 'react-apollo';
114+
import {B} from 'B';
115+
import A from './A';
116+
117+
118+
const QUERY: string =
119+
/* GraphQL */
120+
\`
121+
query Test {
122+
test {
123+
value
124+
...FragmentsComment
125+
}
126+
}
127+
\${A.fragments.test}
128+
\`
129+
130+
export function Example(arg: string) {}`;
131+
132+
const contents = findGraphQLTags(text, '.ts');
133+
expect(contents[0].template).toEqual(`
134+
query Test {
135+
test {
136+
value
137+
...FragmentsComment
138+
}
139+
}
140+
`);
141+
});
142+
143+
it('finds queries with nested template tag expressions', async () => {
144+
const text = `export default {
145+
else: () => gql\` query {} \`
146+
}`;
147+
148+
const contents = findGraphQLTags(text, '.ts');
149+
expect(contents[0].template).toEqual(` query {} `);
150+
});
151+
152+
it('finds queries with template tags inside call expressions', async () => {
153+
const text = `something({
154+
else: () => gql\` query {} \`
155+
})`;
156+
157+
const contents = findGraphQLTags(text, '.ts');
158+
expect(contents[0].template).toEqual(` query {} `);
159+
});
160+
161+
it('ignores non gql tagged templates', async () => {
162+
const text = `
163+
// @flow
164+
import randomthing from 'package';
165+
import type {B} from 'B';
166+
import A from './A';
167+
168+
const QUERY = randomthing\`
169+
query Test {
170+
test {
171+
value
172+
...FragmentsComment
173+
}
174+
}
175+
\${A.fragments.test}
176+
\`
177+
178+
export function Example(arg: string) {}`;
179+
180+
const contents = findGraphQLTags(text, '.js');
181+
expect(contents.length).toEqual(0);
182+
});
183+
184+
it('ignores non gql call expressions with template literals', async () => {
185+
const text = `
186+
// @flow
187+
import randomthing from 'package';
188+
import type {B} from 'B';
189+
import A from './A';
190+
191+
const QUERY = randomthing(\`
192+
query Test {
193+
test {
194+
value
195+
...FragmentsComment
196+
}
197+
}
198+
\${A.fragments.test}
199+
\`);
200+
201+
export function Example(arg: string) {}`;
202+
203+
const contents = findGraphQLTags(text, '.js');
204+
expect(contents.length).toEqual(0);
205+
});
206+
});

0 commit comments

Comments
 (0)