From 4c500249950c8c8a9f29c8b0e2aa913dad0aa28a Mon Sep 17 00:00:00 2001 From: Rikki Schulte Date: Mon, 9 Sep 2024 18:41:02 +0200 Subject: [PATCH] better context detection --- .../__schema__/StarWarsSchema.graphql | 2 +- .../getAutocompleteSuggestions-test.ts | 18 +++++++++++++++++- .../interface/getAutocompleteSuggestions.ts | 19 ++++++++++--------- .../src/parser/getTypeInfo.ts | 7 ++++++- .../graphql-language-service/src/types.ts | 2 ++ 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/graphql-language-service/src/interface/__tests__/__schema__/StarWarsSchema.graphql b/packages/graphql-language-service/src/interface/__tests__/__schema__/StarWarsSchema.graphql index a1707b884e6..42ac95d3774 100644 --- a/packages/graphql-language-service/src/interface/__tests__/__schema__/StarWarsSchema.graphql +++ b/packages/graphql-language-service/src/interface/__tests__/__schema__/StarWarsSchema.graphql @@ -47,7 +47,7 @@ input InputType { } input OneOfInputType @oneOf { - key: String! + key: String value: Int obj: InputType } diff --git a/packages/graphql-language-service/src/interface/__tests__/getAutocompleteSuggestions-test.ts b/packages/graphql-language-service/src/interface/__tests__/getAutocompleteSuggestions-test.ts index caa29710810..348c46a1f3f 100644 --- a/packages/graphql-language-service/src/interface/__tests__/getAutocompleteSuggestions-test.ts +++ b/packages/graphql-language-service/src/interface/__tests__/getAutocompleteSuggestions-test.ts @@ -683,9 +683,14 @@ describe('getAutocompleteSuggestions', () => { }); it('provides correct oneOf input type field suggestions', () => { + const args = [ + { ...inputArgs[0], detail: 'String' }, + inputArgs[1], + inputArgs[2], + ]; expect( testSuggestions('{ oneOfInputTypeTest(oneOf: {', new Position(0, 29)), - ).toEqual(inputArgs); + ).toEqual(args); }); it('provides no more field suggestions once a oneOf field is chosen', () => { @@ -697,6 +702,17 @@ describe('getAutocompleteSuggestions', () => { ).toEqual([]); }); + // TODO: decide if we want this. Discussing with @benjie, we might want to actually give the user flexibility here, + // instead of being strict + // it('provides no more field suggestions once a oneOf field is chose and a user begins typing another field', () => { + // expect( + // testSuggestions( + // '{ oneOfInputTypeTest(oneOf: { value: 2 d', + // new Position(0, 40), + // ), + // ).toEqual([]); + // }); + it('provides correct field name suggestion inside inline fragment', () => { expect( testSuggestions( diff --git a/packages/graphql-language-service/src/interface/getAutocompleteSuggestions.ts b/packages/graphql-language-service/src/interface/getAutocompleteSuggestions.ts index 8a22051c42b..2c145eab211 100644 --- a/packages/graphql-language-service/src/interface/getAutocompleteSuggestions.ts +++ b/packages/graphql-language-service/src/interface/getAutocompleteSuggestions.ts @@ -312,20 +312,21 @@ export function getAutocompleteSuggestions( (kind === RuleKinds.OBJECT_FIELD && step === 0)) && typeInfo.objectFieldDefs ) { - const objectFields = objectValues(typeInfo.objectFieldDefs); - const completionKind = - kind === RuleKinds.OBJECT_VALUE - ? CompletionItemKind.Value - : CompletionItemKind.Field; // @oneOf logic! + console.log(state.prevState?.prevState?.kind, !!typeInfo.inputType); if ( - typeInfo?.inputType && - 'isOneOf' in typeInfo.inputType && - typeInfo.inputType.isOneOf === true && - context.token.string !== '{' + typeInfo?.inputType?.isOneOf === true && + (state.prevState?.prevState?.kind !== 'Argument' || token.string !== '{') ) { + // return empty array early if a oneOf field has already been provided return []; } + const objectFields = objectValues(typeInfo.objectFieldDefs); + const completionKind = + kind === RuleKinds.OBJECT_VALUE + ? CompletionItemKind.Value + : CompletionItemKind.Field; + return hintList( token, objectFields.map(field => ({ diff --git a/packages/graphql-language-service/src/parser/getTypeInfo.ts b/packages/graphql-language-service/src/parser/getTypeInfo.ts index f0f8d1ae8d7..d2fb371513d 100644 --- a/packages/graphql-language-service/src/parser/getTypeInfo.ts +++ b/packages/graphql-language-service/src/parser/getTypeInfo.ts @@ -213,8 +213,11 @@ export function getTypeInfo( } } } - inputType = argDef?.type; + if (argDef?.type) { + inputType = argDef.type; + } break; + case RuleKinds.VARIABLE_DEFINITION: case RuleKinds.VARIABLE: type = inputType; @@ -241,6 +244,8 @@ export function getTypeInfo( objectType instanceof GraphQLInputObjectType ? objectType.getFields() : null; + inputType = objectType; + console.log(inputType); break; // TODO: needs tests case RuleKinds.OBJECT_FIELD: diff --git a/packages/graphql-language-service/src/types.ts b/packages/graphql-language-service/src/types.ts index 52b77d843f9..4b6e9f4280e 100644 --- a/packages/graphql-language-service/src/types.ts +++ b/packages/graphql-language-service/src/types.ts @@ -29,6 +29,8 @@ import type { GraphQLObjectType, GraphQLType, GraphQLDirective, + GraphQLInputType, + GraphQLInputObjectType, } from 'graphql'; export type Maybe = T | null | undefined;