Skip to content

Commit

Permalink
feat: introduce graphql mode for codemirror
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewBastin committed Sep 10, 2021
1 parent 41a02f0 commit 003400c
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 1 deletion.
3 changes: 2 additions & 1 deletion components/graphql/RequestOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ import { getCurrentStrategyID } from "~/helpers/network"
import { makeGQLRequest } from "~/helpers/types/HoppGQLRequest"
import { useCodemirror } from "~/helpers/editor/codemirror"
import "codemirror/mode/javascript/javascript"
import "~/helpers/editor/modes/graphql"
import jsonLinter from "~/helpers/editor/linting/json"
import { createGQLQueryLinter } from "~/helpers/editor/linting/gqlQuery"
import queryCompleter from "~/helpers/editor/completion/gqlQuery"
Expand Down Expand Up @@ -365,7 +366,7 @@ const schemaString = useReadonlyStream(props.conn.schema$, null)
useCodemirror(queryEditor, gqlQueryString, {
extendedEditorConfig: {
mode: "application/ld+json",
mode: "graphql",
},
linter: createGQLQueryLinter(schemaString),
completer: queryCompleter(schemaString),
Expand Down
80 changes: 80 additions & 0 deletions helpers/editor/modes/graphql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2021 GraphQL Contributors
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

import CodeMirror from "codemirror"
import {
LexRules,
ParseRules,
isIgnored,
onlineParser,
State,
} from "graphql-language-service-parser"

/**
* The GraphQL mode is defined as a tokenizer along with a list of rules, each
* of which is either a function or an array.
*
* * Function: Provided a token and the stream, returns an expected next step.
* * Array: A list of steps to take in order.
*
* A step is either another rule, or a terminal description of a token. If it
* is a rule, that rule is pushed onto the stack and the parsing continues from
* that point.
*
* If it is a terminal description, the token is checked against it using a
* `match` function. If the match is successful, the token is colored and the
* rule is stepped forward. If the match is unsuccessful, the remainder of the
* rule is skipped and the previous rule is advanced.
*
* This parsing algorithm allows for incremental online parsing within various
* levels of the syntax tree and results in a structured `state` linked-list
* which contains the relevant information to produce valuable typeaheads.
*/
CodeMirror.defineMode("graphql", (config) => {
const parser = onlineParser({
eatWhitespace: (stream) => stream.eatWhile(isIgnored),
lexRules: LexRules,
parseRules: ParseRules,
editorConfig: { tabSize: 2 },
})

return {
config,
startState: parser.startState,
token: parser.token as unknown as CodeMirror.Mode<any>["token"], // TODO: Check if the types are indeed compatible
indent,
electricInput: /^\s*[})\]]/,
fold: "brace",
lineComment: "#",
closeBrackets: {
pairs: '()[]{}""',
explode: "()[]{}",
},
}
})

// Seems the electricInput type in @types/codemirror is wrong (i.e it is written as electricinput instead of electricInput)
function indent(
this: CodeMirror.Mode<any> & {
electricInput?: RegExp
config?: CodeMirror.EditorConfiguration
},
state: State,
textAfter: string
) {
const levels = state.levels
// If there is no stack of levels, use the current level.
// Otherwise, use the top level, pre-emptively dedenting for close braces.
const level =
!levels || levels.length === 0
? state.indentLevel
: levels[levels.length - 1] -
(this.electricInput?.test(textAfter) ? 1 : 0)
return (level || 0) * (this.config?.indentUnit || 0)
}
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"fuse.js": "^6.4.6",
"graphql": "^15.5.0",
"graphql-language-service-interface": "^2.8.4",
"graphql-language-service-parser": "^1.9.2",
"json-loader": "^0.5.7",
"lodash": "^4.17.21",
"mustache": "^4.2.0",
Expand Down

0 comments on commit 003400c

Please sign in to comment.