Prism.languages.graphql = { 'comment': /#.*/, 'description': { pattern: /(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i, greedy: true, alias: 'string', inside: { 'language-markdown': { pattern: /(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/, lookbehind: true, inside: Prism.languages.markdown } } }, 'string': { pattern: /"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/, greedy: true }, 'number': /(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i, 'boolean': /\b(?:false|true)\b/, 'variable': /\$[a-z_]\w*/i, 'directive': { pattern: /@[a-z_]\w*/i, alias: 'function' }, 'attr-name': { pattern: /\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i, greedy: true }, 'atom-input': { pattern: /\b[A-Z]\w*Input\b/, alias: 'class-name' }, 'scalar': /\b(?:Boolean|Float|ID|Int|String)\b/, 'constant': /\b[A-Z][A-Z_\d]*\b/, 'class-name': { pattern: /(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/, lookbehind: true }, 'fragment': { pattern: /(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/, lookbehind: true, alias: 'function' }, 'definition-mutation': { pattern: /(\bmutation\s+)[a-zA-Z_]\w*/, lookbehind: true, alias: 'function' }, 'definition-query': { pattern: /(\bquery\s+)[a-zA-Z_]\w*/, lookbehind: true, alias: 'function' }, 'keyword': /\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/, 'operator': /[!=|&]|\.{3}/, 'property-query': /\w+(?=\s*\()/, 'object': /\w+(?=\s*\{)/, 'punctuation': /[!(){}\[\]:=,]/, 'property': /\w+/ }; Prism.hooks.add('after-tokenize', function afterTokenizeGraphql(env) { if (env.language !== 'graphql') { return; } /** * get the graphql token stream that we want to customize * * @typedef {InstanceType} Token * @type {Token[]} */ var validTokens = env.tokens.filter(function (token) { return typeof token !== 'string' && token.type !== 'comment' && token.type !== 'scalar'; }); var currentIndex = 0; /** * Returns whether the token relative to the current index has the given type. * * @param {number} offset * @returns {Token | undefined} */ function getToken(offset) { return validTokens[currentIndex + offset]; } /** * Returns whether the token relative to the current index has the given type. * * @param {readonly string[]} types * @param {number} [offset=0] * @returns {boolean} */ function isTokenType(types, offset) { offset = offset || 0; for (var i = 0; i < types.length; i++) { var token = getToken(i + offset); if (!token || token.type !== types[i]) { return false; } } return true; } /** * Returns the index of the closing bracket to an opening bracket. * * It is assumed that `token[currentIndex - 1]` is an opening bracket. * * If no closing bracket could be found, `-1` will be returned. * * @param {RegExp} open * @param {RegExp} close * @returns {number} */ function findClosingBracket(open, close) { var stackHeight = 1; for (var i = currentIndex; i < validTokens.length; i++) { var token = validTokens[i]; var content = token.content; if (token.type === 'punctuation' && typeof content === 'string') { if (open.test(content)) { stackHeight++; } else if (close.test(content)) { stackHeight--; if (stackHeight === 0) { return i; } } } } return -1; } /** * Adds an alias to the given token. * * @param {Token} token * @param {string} alias * @returns {void} */ function addAlias(token, alias) { var aliases = token.alias; if (!aliases) { token.alias = aliases = []; } else if (!Array.isArray(aliases)) { token.alias = aliases = [aliases]; } aliases.push(alias); } for (; currentIndex < validTokens.length;) { var startToken = validTokens[currentIndex++]; // add special aliases for mutation tokens if (startToken.type === 'keyword' && startToken.content === 'mutation') { // any array of the names of all input variables (if any) var inputVariables = []; if (isTokenType(['definition-mutation', 'punctuation']) && getToken(1).content === '(') { // definition currentIndex += 2; // skip 'definition-mutation' and 'punctuation' var definitionEnd = findClosingBracket(/^\($/, /^\)$/); if (definitionEnd === -1) { continue; } // find all input variables for (; currentIndex < definitionEnd; currentIndex++) { var t = getToken(0); if (t.type === 'variable') { addAlias(t, 'variable-input'); inputVariables.push(t.content); } } currentIndex = definitionEnd + 1; } if (isTokenType(['punctuation', 'property-query']) && getToken(0).content === '{') { currentIndex++; // skip opening bracket addAlias(getToken(0), 'property-mutation'); if (inputVariables.length > 0) { var mutationEnd = findClosingBracket(/^\{$/, /^\}$/); if (mutationEnd === -1) { continue; } // give references to input variables a special alias for (var i = currentIndex; i < mutationEnd; i++) { var varToken = validTokens[i]; if (varToken.type === 'variable' && inputVariables.indexOf(varToken.content) >= 0) { addAlias(varToken, 'variable-input'); } } } } } } });