Skip to content

Commit

Permalink
feat: disable 'did you mean x' during validation
Browse files Browse the repository at this point in the history
  • Loading branch information
n1ru4l committed Jan 28, 2022
1 parent f597c69 commit e455004
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 20 deletions.
5 changes: 5 additions & 0 deletions src/validation/ValidationContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand All @@ -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]() {
Expand Down
22 changes: 13 additions & 9 deletions src/validation/rules/FieldsOnCorrectTypeRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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));
}
}

// Report an error, including helpful suggestions.
Expand Down
8 changes: 7 additions & 1 deletion src/validation/rules/KnownArgumentNamesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
),
);
Expand Down
14 changes: 10 additions & 4 deletions src/validation/rules/KnownTypeNamesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,17 @@ export function KnownTypeNamesRule(
typeName,
isSDL ? standardTypeNames.concat(typeNames) : typeNames,
);
let suggestion = '';

if (
(context as ValidationContext).didYouMean == null ||
(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),
);
}
},
Expand Down
15 changes: 10 additions & 5 deletions src/validation/rules/ValuesOfCorrectTypeRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
),
);
Expand Down
3 changes: 2 additions & 1 deletion src/validation/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function validate(
schema: GraphQLSchema,
documentAST: DocumentNode,
rules: ReadonlyArray<ValidationRule> = 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),
Expand Down Expand Up @@ -68,6 +68,7 @@ export function validate(
}
errors.push(error);
},
options?.didYouMean
);

// This uses a specialized visitor which runs multiple visitors in parallel,
Expand Down

0 comments on commit e455004

Please sign in to comment.