Mirror: TypeScript LSP plugin that finds GraphQL documents in your code and provides diagnostics, auto-complete and hover-information.

add watcher

Changed files
+29 -11
src
+15 -3
src/getSchema.ts
···
-
import { GraphQLSchema, buildSchema } from 'graphql'
+
import { GraphQLSchema, buildSchema, buildClientSchema } from 'graphql'
import path from 'path'
import fs from 'fs'
-
export const loadSchema = (root: string, schema: string): GraphQLSchema => {
+
export const loadSchema = (root: string, schema: string): { current: GraphQLSchema | null } => {
+
const ref: { current: GraphQLSchema | null } = { current: null }
+
const isJson = schema.endsWith('json');
const resolvedPath = path.resolve(path.dirname(root), schema)
const contents = fs.readFileSync(resolvedPath, 'utf-8')
-
return buildSchema(contents)
+
+
fs.watchFile(resolvedPath, () => {
+
const contents = fs.readFileSync(resolvedPath, 'utf-8')
+
const parsedSchema = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents)
+
ref.current = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents)
+
return ref
+
})
+
+
ref.current = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents)
+
+
return ref
}
+9 -7
src/index.ts
···
info.project.projectService.logger.info(
"Setting up the GraphQL Plugin"
);
+
// TODO: our config most likely needs to support
+
// a scalars config as well
const tagTemplate = info.config.template || 'gql';
const proxy = createBasicDecorator(info);
-
// TODO: we have to initialize a watcher for schema changes
const schema = loadSchema(info.project.getProjectName(), info.config.schema);
proxy.getSemanticDiagnostics = (filename: string): ts.Diagnostic[] => {
···
// This assumes a prefix of gql`
let startingPosition = node.pos + 4
-
return getDiagnostics(text, schema).map(x => {
+
return getDiagnostics(text, schema.current).map(x => {
const { start, end } = x.range;
// We add the start.line to account for newline characters which are
···
parts[parts.length - 1] = nameParts.join('.')
// TODO: we might only want to run this onSave/when file isn't dirty
-
generateTypedDocumentNodes(schema, parts.join('/'), texts.join('\n')).then(() => {
+
// alternatively we could set up a watcher to react to saves
+
generateTypedDocumentNodes(schema.current, parts.join('/'), texts.join('\n')).then(() => {
nodes.forEach((node, i) => {
const queryText = texts[i] || '';
const parsed = parse(queryText);
···
const text = resolveTemplate(node, filename, info)
const foundToken = getToken(template, cursorPosition)
-
if (!foundToken) return originalCompletions
+
if (!foundToken || !schema.current) return originalCompletions
// TODO: this does not include fragmentSpread suggestions
-
const suggestions = getAutocompleteSuggestions(schema, text, new Cursor(foundToken.line, foundToken.start))
+
const suggestions = getAutocompleteSuggestions(schema.current, text, new Cursor(foundToken.line, foundToken.start))
const result: ts.WithMetadata<ts.CompletionInfo> = {
isGlobalCompletion: false,
···
const text = resolveTemplate(node, filename, info)
const foundToken = getToken(template, cursorPosition)
-
if (!foundToken) return originalInfo
+
if (!foundToken || !schema.current) return originalInfo
-
const hoverInfo = getHoverInformation(schema as GraphQLSchema, text, new Cursor(foundToken.line, foundToken.start))
+
const hoverInfo = getHoverInformation(schema.current, text, new Cursor(foundToken.line, foundToken.start))
const result: ts.QuickInfo = {
kind: ts.ScriptElementKind.string,
textSpan: {
+5 -1
src/types/generate.ts
···
import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations'
import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node'
-
export const generateTypedDocumentNodes = async (schema: GraphQLSchema, outputFile: string, doc: string) => {
+
export const generateTypedDocumentNodes = async (schema: GraphQLSchema | null, outputFile: string, doc: string) => {
+
if (!schema) return;
+
const config = {
documents: [
{
···
filename: outputFile,
schema: parse(printSchema(schema)),
plugins: [
+
// TODO: there's optimisations to be had here where we move the typescript and typescript-operations
+
// to a global __generated__ folder and import from it.
{ 'typescript': {} },
{ 'typescript-operations': {} },
{ 'typed-document-node': {} },