From 64297602a0e8665708270bd1b726f5f612635b77 Mon Sep 17 00:00:00 2001 From: Laurin Quast Date: Fri, 28 Jan 2022 09:12:02 +0100 Subject: [PATCH] feat: disable 'did you mean x' during validation --- src/validation/ValidationContext.ts | 5 +++++ .../rules/FieldsOnCorrectTypeRule.ts | 22 +++++++++++-------- .../rules/KnownArgumentNamesRule.ts | 8 ++++++- src/validation/rules/KnownTypeNamesRule.ts | 15 +++++++++---- .../rules/ValuesOfCorrectTypeRule.ts | 15 ++++++++----- src/validation/validate.ts | 6 ++++- 6 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/validation/ValidationContext.ts b/src/validation/ValidationContext.ts index f6944a6ebd..f9c7db679e 100644 --- a/src/validation/ValidationContext.ts +++ b/src/validation/ValidationContext.ts @@ -162,6 +162,8 @@ export class SDLValidationContext extends ASTValidationContext { export type SDLValidationRule = (context: SDLValidationContext) => ASTVisitor; export class ValidationContext extends ASTValidationContext { + public readonly didYouMean: boolean; + private _schema: GraphQLSchema; private _typeInfo: TypeInfo; private _variableUsages: Map< @@ -179,12 +181,15 @@ export class ValidationContext extends ASTValidationContext { ast: DocumentNode, typeInfo: TypeInfo, onError: (error: GraphQLError) => void, + /** Whether the "did you mean x" suggestions should be enabled. */ + didYouMean?: boolean, ) { super(ast, onError); this._schema = schema; this._typeInfo = typeInfo; this._variableUsages = new Map(); this._recursiveVariableUsages = new Map(); + this.didYouMean = didYouMean == null ? true : didYouMean; } get [Symbol.toStringTag]() { diff --git a/src/validation/rules/FieldsOnCorrectTypeRule.ts b/src/validation/rules/FieldsOnCorrectTypeRule.ts index e9d220efef..421243a3a8 100644 --- a/src/validation/rules/FieldsOnCorrectTypeRule.ts +++ b/src/validation/rules/FieldsOnCorrectTypeRule.ts @@ -42,15 +42,19 @@ export function FieldsOnCorrectTypeRule( const schema = context.getSchema(); const fieldName = node.name.value; - // First determine if there are any suggested types to condition on. - let suggestion = didYouMean( - 'to use an inline fragment on', - getSuggestedTypeNames(schema, type, fieldName), - ); - - // If there are no suggested types, then perhaps this was a typo? - if (suggestion === '') { - suggestion = didYouMean(getSuggestedFieldNames(type, fieldName)); + let suggestion = ''; + + if (context.didYouMean) { + // First determine if there are any suggested types to condition on. + suggestion = didYouMean( + 'to use an inline fragment on', + getSuggestedTypeNames(schema, type, fieldName), + ); + + // If there are no suggested types, then perhaps this was a typo? + if (suggestion === '') { + suggestion = didYouMean(getSuggestedFieldNames(type, fieldName)); + } } // Report an error, including helpful suggestions. diff --git a/src/validation/rules/KnownArgumentNamesRule.ts b/src/validation/rules/KnownArgumentNamesRule.ts index 5f5c4c70b5..84635dc21c 100644 --- a/src/validation/rules/KnownArgumentNamesRule.ts +++ b/src/validation/rules/KnownArgumentNamesRule.ts @@ -35,10 +35,16 @@ export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor { const argName = argNode.name.value; const knownArgsNames = fieldDef.args.map((arg) => arg.name); const suggestions = suggestionList(argName, knownArgsNames); + let suggestion = ''; + + if (context.didYouMean) { + suggestion = didYouMean(suggestions); + } + context.reportError( new GraphQLError( `Unknown argument "${argName}" on field "${parentType.name}.${fieldDef.name}".` + - didYouMean(suggestions), + suggestion, argNode, ), ); diff --git a/src/validation/rules/KnownTypeNamesRule.ts b/src/validation/rules/KnownTypeNamesRule.ts index 4802610a2e..dc6e5d96f1 100644 --- a/src/validation/rules/KnownTypeNamesRule.ts +++ b/src/validation/rules/KnownTypeNamesRule.ts @@ -59,11 +59,18 @@ export function KnownTypeNamesRule( typeName, isSDL ? standardTypeNames.concat(typeNames) : typeNames, ); + let suggestion = ''; + + if ( + (context as ValidationContext).didYouMean == null || + // eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare + (context as ValidationContext).didYouMean === true + ) { + suggestion = didYouMean(suggestedTypes); + } + context.reportError( - new GraphQLError( - `Unknown type "${typeName}".` + didYouMean(suggestedTypes), - node, - ), + new GraphQLError(`Unknown type "${typeName}".` + suggestion, node), ); } }, diff --git a/src/validation/rules/ValuesOfCorrectTypeRule.ts b/src/validation/rules/ValuesOfCorrectTypeRule.ts index 158691c50c..ca8f30faff 100644 --- a/src/validation/rules/ValuesOfCorrectTypeRule.ts +++ b/src/validation/rules/ValuesOfCorrectTypeRule.ts @@ -67,14 +67,19 @@ export function ValuesOfCorrectTypeRule( const parentType = getNamedType(context.getParentInputType()); const fieldType = context.getInputType(); if (!fieldType && isInputObjectType(parentType)) { - const suggestions = suggestionList( - node.name.value, - Object.keys(parentType.getFields()), - ); + let suggestion = ''; + if (context.didYouMean) { + const suggestions = suggestionList( + node.name.value, + Object.keys(parentType.getFields()), + ); + suggestion = didYouMean(suggestions); + } + context.reportError( new GraphQLError( `Field "${node.name.value}" is not defined by type "${parentType.name}".` + - didYouMean(suggestions), + suggestion, node, ), ); diff --git a/src/validation/validate.ts b/src/validation/validate.ts index 7259874240..f955aed6c5 100644 --- a/src/validation/validate.ts +++ b/src/validation/validate.ts @@ -39,7 +39,10 @@ export function validate( schema: GraphQLSchema, documentAST: DocumentNode, rules: ReadonlyArray = specifiedRules, - options?: { maxErrors?: number }, + options: { maxErrors?: number; didYouMean?: boolean } = { + maxErrors: undefined, + didYouMean: true, + }, /** @deprecated will be removed in 17.0.0 */ typeInfo: TypeInfo = new TypeInfo(schema), @@ -68,6 +71,7 @@ export function validate( } errors.push(error); }, + options?.didYouMean, ); // This uses a specialized visitor which runs multiple visitors in parallel,