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

Configure Feed

Select the types of activity you want to include in your feed.

add watcher

+29 -11
+15 -3
src/getSchema.ts
··· 1 - import { GraphQLSchema, buildSchema } from 'graphql' 1 + import { GraphQLSchema, buildSchema, buildClientSchema } from 'graphql' 2 2 import path from 'path' 3 3 import fs from 'fs' 4 4 5 - export const loadSchema = (root: string, schema: string): GraphQLSchema => { 5 + export const loadSchema = (root: string, schema: string): { current: GraphQLSchema | null } => { 6 + const ref: { current: GraphQLSchema | null } = { current: null } 7 + const isJson = schema.endsWith('json'); 6 8 const resolvedPath = path.resolve(path.dirname(root), schema) 7 9 const contents = fs.readFileSync(resolvedPath, 'utf-8') 8 - return buildSchema(contents) 10 + 11 + fs.watchFile(resolvedPath, () => { 12 + const contents = fs.readFileSync(resolvedPath, 'utf-8') 13 + const parsedSchema = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents) 14 + ref.current = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents) 15 + return ref 16 + }) 17 + 18 + ref.current = isJson ? buildClientSchema(JSON.parse(contents)) : buildSchema(contents) 19 + 20 + return ref 9 21 }
+9 -7
src/index.ts
··· 31 31 info.project.projectService.logger.info( 32 32 "Setting up the GraphQL Plugin" 33 33 ); 34 + // TODO: our config most likely needs to support 35 + // a scalars config as well 34 36 const tagTemplate = info.config.template || 'gql'; 35 37 36 38 const proxy = createBasicDecorator(info); 37 39 38 - // TODO: we have to initialize a watcher for schema changes 39 40 const schema = loadSchema(info.project.getProjectName(), info.config.schema); 40 41 41 42 proxy.getSemanticDiagnostics = (filename: string): ts.Diagnostic[] => { ··· 73 74 74 75 // This assumes a prefix of gql` 75 76 let startingPosition = node.pos + 4 76 - return getDiagnostics(text, schema).map(x => { 77 + return getDiagnostics(text, schema.current).map(x => { 77 78 const { start, end } = x.range; 78 79 79 80 // We add the start.line to account for newline characters which are ··· 119 120 parts[parts.length - 1] = nameParts.join('.') 120 121 121 122 // TODO: we might only want to run this onSave/when file isn't dirty 122 - generateTypedDocumentNodes(schema, parts.join('/'), texts.join('\n')).then(() => { 123 + // alternatively we could set up a watcher to react to saves 124 + generateTypedDocumentNodes(schema.current, parts.join('/'), texts.join('\n')).then(() => { 123 125 nodes.forEach((node, i) => { 124 126 const queryText = texts[i] || ''; 125 127 const parsed = parse(queryText); ··· 201 203 const text = resolveTemplate(node, filename, info) 202 204 const foundToken = getToken(template, cursorPosition) 203 205 204 - if (!foundToken) return originalCompletions 206 + if (!foundToken || !schema.current) return originalCompletions 205 207 206 208 // TODO: this does not include fragmentSpread suggestions 207 - const suggestions = getAutocompleteSuggestions(schema, text, new Cursor(foundToken.line, foundToken.start)) 209 + const suggestions = getAutocompleteSuggestions(schema.current, text, new Cursor(foundToken.line, foundToken.start)) 208 210 209 211 const result: ts.WithMetadata<ts.CompletionInfo> = { 210 212 isGlobalCompletion: false, ··· 247 249 const text = resolveTemplate(node, filename, info) 248 250 const foundToken = getToken(template, cursorPosition) 249 251 250 - if (!foundToken) return originalInfo 252 + if (!foundToken || !schema.current) return originalInfo 251 253 252 - const hoverInfo = getHoverInformation(schema as GraphQLSchema, text, new Cursor(foundToken.line, foundToken.start)) 254 + const hoverInfo = getHoverInformation(schema.current, text, new Cursor(foundToken.line, foundToken.start)) 253 255 const result: ts.QuickInfo = { 254 256 kind: ts.ScriptElementKind.string, 255 257 textSpan: {
+5 -1
src/types/generate.ts
··· 6 6 import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations' 7 7 import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node' 8 8 9 - export const generateTypedDocumentNodes = async (schema: GraphQLSchema, outputFile: string, doc: string) => { 9 + export const generateTypedDocumentNodes = async (schema: GraphQLSchema | null, outputFile: string, doc: string) => { 10 + if (!schema) return; 11 + 10 12 const config = { 11 13 documents: [ 12 14 { ··· 20 22 filename: outputFile, 21 23 schema: parse(printSchema(schema)), 22 24 plugins: [ 25 + // TODO: there's optimisations to be had here where we move the typescript and typescript-operations 26 + // to a global __generated__ folder and import from it. 23 27 { 'typescript': {} }, 24 28 { 'typescript-operations': {} }, 25 29 { 'typed-document-node': {} },