Skip to content

Commit 34f24ac

Browse files
GraphQL: Added more detailed tokens (#2939)
Co-authored-by: Michael Schmidt <mitchi5000.ms@googlemail.com>
1 parent 99f3ddc commit 34f24ac

File tree

6 files changed

+194
-19
lines changed

6 files changed

+194
-19
lines changed

components/prism-graphql.js

Lines changed: 171 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,188 @@ Prism.languages.graphql = {
2424
alias: 'function'
2525
},
2626
'attr-name': {
27-
pattern: /\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,
27+
pattern: /[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,
2828
greedy: true
2929
},
30+
'atom-input': {
31+
pattern: /[A-Z]\w*Input(?=!?.*$)/m,
32+
alias: 'class-name'
33+
},
34+
'scalar': /\b(?:Boolean|Float|ID|Int|String)\b/,
35+
'constant': /\b[A-Z][A-Z_\d]*\b/,
3036
'class-name': {
31-
pattern: /(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*)[a-zA-Z_]\w*/,
37+
pattern: /(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,
3238
lookbehind: true
3339
},
3440
'fragment': {
3541
pattern: /(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,
3642
lookbehind: true,
3743
alias: 'function'
3844
},
45+
'definition-mutation': {
46+
pattern: /(\bmutation\s+|\.{3}\s*)[a-zA-Z_]\w*/,
47+
lookbehind: true,
48+
alias: 'function'
49+
},
50+
'definition-query': {
51+
pattern: /(\bquery\s+|\.{3}\s*)[a-zA-Z_]\w*/,
52+
lookbehind: true,
53+
alias: 'function'
54+
},
3955
'keyword': /\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,
4056
'operator': /[!=|&]|\.{3}/,
57+
'property-query': /\w+(?=\s*\()/,
58+
'object': /\w+(?=\s*{)/,
4159
'punctuation': /[!(){}\[\]:=,]/,
42-
'constant': /\b(?!ID\b)[A-Z][A-Z_\d]*\b/
60+
'property': /\w+/
4361
};
62+
63+
Prism.hooks.add('after-tokenize', function afterTokenizeGraphql(env) {
64+
if (env.language !== 'graphql') {
65+
return;
66+
}
67+
68+
/**
69+
* get the graphql token stream that we want to customize
70+
*
71+
* @typedef {InstanceType<import("./prism-core")["Token"]>} Token
72+
* @type {Token[]}
73+
*/
74+
var validTokens = env.tokens.filter(function (token) {
75+
return typeof token !== 'string' && token.type !== 'comment' && token.type !== 'scalar';
76+
});
77+
78+
var currentIndex = 0;
79+
80+
/**
81+
* Returns whether the token relative to the current index has the given type.
82+
*
83+
* @param {number} offset
84+
* @returns {Token | undefined}
85+
*/
86+
function getToken(offset) {
87+
return validTokens[currentIndex + offset];
88+
}
89+
90+
/**
91+
* Returns whether the token relative to the current index has the given type.
92+
*
93+
* @param {readonly string[]} types
94+
* @param {number} [offset=0]
95+
* @returns {boolean}
96+
*/
97+
function isTokenType(types, offset) {
98+
offset = offset || 0;
99+
for (var i = 0; i < types.length; i++) {
100+
var token = getToken(i + offset);
101+
if (!token || token.type !== types[i]) {
102+
return false;
103+
}
104+
}
105+
return true;
106+
}
107+
108+
/**
109+
* Returns the index of the closing bracket to an opening bracket.
110+
*
111+
* It is assumed that `token[currentIndex - 1]` is an opening bracket.
112+
*
113+
* If no closing bracket could be found, `-1` will be returned.
114+
*
115+
* @param {RegExp} open
116+
* @param {RegExp} close
117+
* @returns {number}
118+
*/
119+
function findClosingBracket(open, close) {
120+
var stackHeight = 1;
121+
122+
for (var i = currentIndex; i < validTokens.length; i++) {
123+
var token = validTokens[i];
124+
var content = token.content;
125+
126+
if (token.type === 'punctuation' && typeof content === 'string') {
127+
if (open.test(content)) {
128+
stackHeight++;
129+
} else if (close.test(content)) {
130+
stackHeight--;
131+
132+
if (stackHeight === 0) {
133+
return i;
134+
}
135+
}
136+
}
137+
}
138+
139+
return -1;
140+
}
141+
142+
/**
143+
* Adds an alias to the given token.
144+
*
145+
* @param {Token} token
146+
* @param {string} alias
147+
* @returns {void}
148+
*/
149+
function addAlias(token, alias) {
150+
var aliases = token.alias;
151+
if (!aliases) {
152+
token.alias = aliases = [];
153+
} else if (!Array.isArray(aliases)) {
154+
token.alias = aliases = [aliases];
155+
}
156+
aliases.push(alias);
157+
}
158+
159+
for (; currentIndex < validTokens.length;) {
160+
var startToken = validTokens[currentIndex++];
161+
162+
// add special aliases for mutation tokens
163+
if (startToken.type === 'keyword' && startToken.content === 'mutation') {
164+
// any array of the names of all input variables (if any)
165+
var inputVariables = [];
166+
167+
if (isTokenType(['definition-mutation', 'punctuation']) && getToken(1).content === '(') {
168+
// definition
169+
170+
currentIndex += 2; // skip 'definition-mutation' and 'punctuation'
171+
172+
var definitionEnd = findClosingBracket(/^\($/, /^\)$/);
173+
if (definitionEnd === -1) {
174+
continue;
175+
}
176+
177+
// find all input variables
178+
for (; currentIndex < definitionEnd; currentIndex++) {
179+
var t = getToken(0);
180+
if (t.type === 'variable') {
181+
addAlias(t, 'variable-input');
182+
inputVariables.push(t.content);
183+
}
184+
}
185+
186+
currentIndex = definitionEnd + 1;
187+
}
188+
189+
if (isTokenType(['punctuation', 'property-query']) && getToken(0).content === '{') {
190+
currentIndex++; // skip opening bracket
191+
192+
addAlias(getToken(0), 'property-mutation');
193+
194+
if (inputVariables.length > 0) {
195+
var mutationEnd = findClosingBracket(/^{$/, /^}$/);
196+
if (mutationEnd === -1) {
197+
continue;
198+
}
199+
200+
// give references to input variables a special alias
201+
for (var i = currentIndex; i < mutationEnd; i++) {
202+
var varToken = validTokens[i];
203+
if (varToken.type === 'variable' && inputVariables.indexOf(varToken.content) >= 0) {
204+
addAlias(varToken, 'variable-input');
205+
}
206+
}
207+
}
208+
}
209+
}
210+
}
211+
});

components/prism-graphql.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/languages/graphql/attr-name_feature.test

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,35 @@
1212

1313
["attr-name", "zuck"],
1414
["punctuation", ":"],
15-
" user",
15+
["property-query", "user"],
1616
["punctuation", "("],
1717
["attr-name", "id"],
1818
["punctuation", ":"],
1919
["number", "4"],
2020
["punctuation", ")"],
2121
["punctuation", "{"],
22-
"\r\n\t\tname\r\n\t",
22+
23+
["property", "name"],
24+
2325
["punctuation", "}"],
2426

2527
["attr-name", "foo"],
2628
["punctuation", "("],
2729
["attr-name", "bar"],
2830
["punctuation", ":"],
29-
" Int ",
31+
["scalar", "Int"],
3032
["operator", "="],
3133
["number", "0"],
3234
["punctuation", ","],
3335
["attr-name", "baz"],
3436
["punctuation", ":"],
35-
" String ",
37+
["scalar", "String"],
3638
["operator", "="],
3739
["string", "\"(\""],
3840
["punctuation", ")"],
3941
["punctuation", ":"],
4042
["punctuation", "["],
41-
"Int",
43+
["scalar", "Int"],
4244
["operator", "!"],
4345
["punctuation", "]"],
4446
["operator", "!"],
@@ -48,4 +50,4 @@
4850

4951
----------------------------------------------------
5052

51-
Checks for aliases, parameter names, etc.
53+
Checks for aliases, parameter names, etc.

tests/languages/graphql/constant_feature.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ enum Color {
2121

2222
["punctuation", "{"],
2323

24-
"\r\n\tfoo",
24+
["property-query", "foo"],
2525
["punctuation", "("],
2626
["attr-name", "bar"],
2727
["punctuation", ":"],
2828
["constant", "RED"],
2929
["punctuation", ")"],
3030
["punctuation", "{"],
3131

32-
"\r\n\t\tbaz\r\n\t",
32+
["property", "baz"],
3333

3434
["punctuation", "}"],
3535

tests/languages/graphql/fragment_feature.test

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,22 @@ fragment frag on FooBar {
1111

1212
[
1313
["punctuation", "{"],
14-
["operator", "..."],
15-
["fragment", "frag"],
14+
["operator", "..."], ["fragment", "frag"],
1615
["punctuation", "}"],
1716

1817
["keyword", "fragment"],
1918
["fragment", "frag"],
2019
["keyword", "on"],
2120
["class-name", "FooBar"],
2221
["punctuation", "{"],
23-
"\r\n\tfoo\r\n\tbar\r\n",
22+
23+
["property", "foo"],
24+
25+
["property", "bar"],
26+
2427
["punctuation", "}"]
2528
]
2629

2730
----------------------------------------------------
2831

29-
Checks for fragments.
32+
Checks for fragments.

tests/languages/javascript!+graphql+js-templates/graphql_inclusion.test

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,31 @@ graphql.experimental`{ foo }`
1010
["template-punctuation", "`"],
1111
["graphql", [
1212
["punctuation", "{"],
13-
" foo ",
13+
["property", "foo"],
1414
["punctuation", "}"]
1515
]],
1616
["template-punctuation", "`"]
1717
]],
18+
1819
"\r\ngraphql",
1920
["template-string", [
2021
["template-punctuation", "`"],
2122
["graphql", [
2223
["punctuation", "{"],
23-
" foo ",
24+
["property", "foo"],
2425
["punctuation", "}"]
2526
]],
2627
["template-punctuation", "`"]
2728
]],
29+
2830
"\r\ngraphql",
2931
["punctuation", "."],
3032
"experimental",
3133
["template-string", [
3234
["template-punctuation", "`"],
3335
["graphql", [
3436
["punctuation", "{"],
35-
" foo ",
37+
["property", "foo"],
3638
["punctuation", "}"]
3739
]],
3840
["template-punctuation", "`"]

0 commit comments

Comments
 (0)