New GraphQL Sourcegraph extension

By Chris Wendt on December 5, 2018


Sourcegraph extensions make it easy to build code intelligence using existing language analysis tools that don't necessarily speak LSP (the Language Server Protocol).

GraphQL is one of these languages that has a language analysis tool and I spent a few days building a Sourcegraph extension for it.

You can try it out on Sourcegraph.com by first enabling the GraphQL extension then visiting a sample GraphQL file (beware this is relatively experimental - only hover tooltips and jump-to-definition within the same file work).

image

The first step was to start with the activate() function that will run when the Sourcegraph extension is run:

export function activate(): void {}

Then I grab the address of the GraphQL language server from a user setting:

 export function activate(): void {
+  const address = sourcegraph.configuration.get<Settings>().get('graphql.langserver-address')
 }

Then I register a callback that will run when the user hovers over something in a GraphQL file:

 export function activate(): void {
   const address = sourcegraph.configuration.get<Settings>().get('graphql.langserver-address')

+  sourcegraph.languages.registerHoverProvider([{ pattern: '*.{graphql,gql}'}], {
+    provideHover: async (doc, pos) => {
+        return ajax({
+            method: 'POST',
+            url: address,
+            body: JSON.stringify({ method: 'hover', doc, pos }),
+            responseType: 'json',
+            headers: {
+                'Content-Type': 'application/json',
+            },
+        })
+    }
+  })
 }

It sends a request to a https://github.com/chrismwendt/graphql-ws-langserver running elsewhere.

Then I convert the response to something that the Sourcegraph extension API understands (with Python syntax highlighting to recognize comment lines starting with #)

 export function activate(): void {
   const address = sourcegraph.configuration.get<Settings>().get('graphql.langserver-address')

   sourcegraph.languages.registerHoverProvider(docSelector, {
     ...
   })
+    .then(response => {
+        return (
+            response &&
+            response.response &&
+            response.response.contents && {
+                contents: {
+                    // python syntax highlighting works pretty well for GraphQL
+                    value: '```python\n' + response.response.contents.join('\n') + '\n```',
+                    kind: sourcegraph.MarkupKind.Markdown,
+                },
+            }
+        )
+    })
 }

Check out the repository for the extension and the server component.