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.

support fragment suggestions

+17 -12
+1 -1
example/src/index.generated.ts
··· 116 116 117 117 export const PokemonFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"pokemonFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Pokemon"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]} as unknown as DocumentNode<PokemonFieldsFragment, unknown>; 118 118 export const PokemonsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Pokemons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pokemons"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode<PokemonsQuery, PokemonsQueryVariables>; 119 - export const PokemonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Pokemon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pokemon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"StringValue","value":"1","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode<PokemonQuery, PokemonQueryVariables>; 119 + export const PokemonDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Pokemon"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pokemon"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"StringValue","value":"1","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"pokemonFields"}}]}}]}},...PokemonFieldsFragmentDoc.definitions]} as unknown as DocumentNode<PokemonQuery, PokemonQueryVariables>;
+5 -1
example/src/index.ts
··· 1 1 import { createClient, gql } from '@urql/core' 2 2 import { PokemonFields } from './fragment' 3 3 4 + // testing stuffzzzzzzzz 5 + 4 6 const Pokemons = gql` 5 7 query Pokemons { 6 8 pokemons { ··· 17 19 pokemon(id: "1") { 18 20 id 19 21 name 22 + ...pokemonFields 20 23 } 21 24 } 22 25 ··· 24 27 ` as typeof import('./index.generated').PokemonDocument 25 28 26 29 const urqlClient = createClient({ 27 - url: 'http://localhost:3000/api' 30 + url: '', 31 + exchanges: [] 28 32 }); 29 33 30 34 urqlClient.query(Pokemons).toPromise().then(result => {
+11 -10
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 35 const tagTemplate = info.config.template || 'gql'; 37 36 38 37 const proxy = createBasicDecorator(info); ··· 75 74 const lines = text.split('\n') 76 75 77 76 let startingPosition = node.pos + (tagTemplate.length + 1) 78 - // TODO: roll our own diagnostic here for operations without an operationName 79 - // we can't generate typedDocumentNodes for those hence we will warn our user 80 77 return getDiagnostics(text, schema.current).map(x => { 81 78 const { start, end } = x.range; 82 79 ··· 120 117 nameParts[nameParts.length - 1] = 'generated.ts' 121 118 parts[parts.length - 1] = nameParts.join('.') 122 119 123 - // TODO: we might only want to run this onSave/when file isn't dirty 124 - // alternatively we could set up a watcher to react to saves 125 120 generateTypedDocumentNodes(schema.current, parts.join('/'), texts.join('\n')).then(() => { 126 121 nodes.forEach((node, i) => { 127 122 const queryText = texts[i] || ''; ··· 147 142 // This checks whether one of the children is an import-type 148 143 // which is a short-circuit if there is no as 149 144 const typeImport = parentChildren.find(x => isImportTypeNode(x)) as ImportTypeNode 150 - if (typeImport && typeImport.getText() === exportName) return; 145 + if (typeImport && typeImport.getText().includes(exportName)) return; 151 146 152 147 const span = { length: 1, start: node.end }; 153 148 const text = source.text.substring(0, span.start) + imp + source.text.substring(span.start + span.length, source.text.length); 154 - 155 149 const scriptInfo = info.project.projectService.getScriptInfo(filename); 156 150 const snapshot = scriptInfo!.getSnapshot(); 157 151 ··· 211 205 212 206 if (!foundToken || !schema.current) return originalCompletions 213 207 214 - // TODO: this does not include fragmentSpread suggestions 215 208 const suggestions = getAutocompleteSuggestions(schema.current, text, new Cursor(foundToken.line, foundToken.start)) 216 209 210 + const parsed = parse(text); 211 + const fragments = parsed.definitions.filter(x => x.kind === Kind.FRAGMENT_DEFINITION) as Array<FragmentDefinitionNode> 212 + 217 213 const result: ts.WithMetadata<ts.CompletionInfo> = { 218 214 isGlobalCompletion: false, 219 215 isMemberCompletion: false, ··· 221 217 entries: [...suggestions.map(suggestion => ({ 222 218 kind: ScriptElementKind.variableElement, 223 219 name: suggestion.label, 220 + kindModifiers: 'declare', 221 + sortText: suggestion.sortText || '0', 222 + })), ...fragments.map(fragment => ({ 223 + kind: ScriptElementKind.variableElement, 224 + name: fragment.name.value, 225 + insertText: '...' + fragment.name.value, 224 226 kindModifiers: 'declare', 225 227 sortText: '0', 226 228 })), ...originalCompletions.entries], ··· 247 249 node = node.parent 248 250 } 249 251 250 - // TODO: visualize fragment-data 251 252 if (isTaggedTemplateExpression(node)) { 252 253 const { template, tag } = node; 253 254 if (!isIdentifier(tag) || tag.text !== tagTemplate) return originalInfo;