UNPKG

graphql

Version:

A Query Language and Runtime which can target any service.

1 lines 30.4 kB
{"version":3,"file":"ValidationContext.js","sourceRoot":"","sources":["../../src/validation/ValidationContext.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,IAAI,EAAE,8BAA6B;AAE5C,OAAO,EAAE,KAAK,EAAE,gCAA+B;AAc/C,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,kCAAiC;AAkBvE,MAAM,OAAO,oBAAoB;IAU/B,YAAY,GAAiB,EAAE,OAAsC;QACnE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,gBAAgB,GAAG,IAAI,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,+BAA+B,GAAG,IAAI,GAAG,EAAE,CAAC;QACjD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,sBAAsB,CAAC;IAChC,CAAC;IAED,WAAW,CAAC,KAAmB;QAC7B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,WAAW,CAAC,IAAY;QACtB,IAAI,SAAyC,CAAC;QAC9C,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,CAAC;gBACrD,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,mBAAmB,EAAE,CAAC;oBAC9C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;gBAC1C,CAAC;YACH,CAAC;YACD,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC9B,CAAC;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,kBAAkB,CAChB,IAAsB;QAEtB,IAAI,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,WAAW,GAA4B,CAAC,IAAI,CAAC,CAAC;YACpD,IAAI,GAAiC,CAAC;YACtC,OAAO,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;gBACjC,KAAK,MAAM,SAAS,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;oBACvC,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,eAAe,EAAE,CAAC;wBAC5C,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBAC1B,CAAC;yBAAM,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;wBAClC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,iCAAiC,CAC/B,SAAkC;QAElC,IAAI,SAAS,GAAG,IAAI,CAAC,+BAA+B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,EAAE,CAAC;YACf,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;YACzC,MAAM,YAAY,GAA4B,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YACvE,IAAI,IAAkC,CAAC;YACvC,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;gBACnC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;oBACnC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAClC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;wBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;wBAC5C,IAAI,QAAQ,EAAE,CAAC;4BACb,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;4BACzB,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;wBAC3C,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,CAAC,+BAA+B,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AAMD,MAAM,OAAO,oBAAqB,SAAQ,oBAAoB;IAG5D,YACE,GAAiB,EACjB,MAA4B,EAC5B,OAAsC;QAEtC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,IAAI,eAAe;QACjB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAa,CAAC,MAAM,CAAC,WAAW,CAAC;QAC/B,OAAO,sBAAsB,CAAC;IAChC,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF;AAMD,MAAM,OAAO,iBAAkB,SAAQ,oBAAoB;IAgDzD,YACE,MAAqB,EACrB,GAAiB,EACjB,QAAkB,EAClB,OAAsC,EACtC,eAAgC;QAEhC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;QACjC,IAAI,CAAC,wBAAwB,GAAG,IAAI,GAAG,EAAE,CAAC;QAC1C,IAAI,CAAC,gBAAgB,GAAG,eAAe,IAAI,KAAK,CAAC;IACnD,CAAC;IAMD,IAAa,CAAC,MAAM,CAAC,WAAW,CAAC;QAC/B,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAMD,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IA0BD,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAgCD,iBAAiB,CAAC,IAA0B;QAC1C,IAAI,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,SAAS,GAAyB,EAAE,CAAC;YAC3C,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAC3B,IAAI,CAAC,OAAO,EACZ,SAAS,EACT,IAAI,CAAC,SAAS,CAAC,0BAA0B,EAAE,CAC5C,CAAC;YACF,MAAM,kBAAkB,GACtB,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5D,KAAK,CACH,IAAI,EACJ,iBAAiB,CAAC,QAAQ,EAAE;gBAC1B,kBAAkB,EAAE,GAAG,EAAE,CAAC,KAAK;gBAC/B,QAAQ,CAAC,QAAQ;oBACf,IAAI,0BAA0B,CAAC;oBAC/B,IAAI,kBAAkB,EAAE,CAAC;wBACvB,MAAM,iBAAiB,GAAG,QAAQ,CAAC,0BAA0B,EAAE,CAC7D,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAC9B,CAAC;wBAEF,0BAA0B;4BACxB,iBAAiB,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBAClE,SAAS,CAAC,IAAI,CAAC;4BACb,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,QAAQ,CAAC,YAAY,EAAE;4BAC7B,UAAU,EAAE,QAAQ,CAAC,kBAAkB,EAAE;4BACzC,YAAY,EAAE,SAAS;4BACvB,0BAA0B;yBAC3B,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,SAAS,CAAC,IAAI,CAAC;4BACb,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,QAAQ,CAAC,YAAY,EAAE;4BAC7B,UAAU,EAAE,QAAQ,CAAC,kBAAkB,EAAE;4BACzC,YAAY,EAAE,QAAQ,CAAC,eAAe,EAAE;4BACxC,0BAA0B,EAAE,SAAS;yBACtC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;aACF,CAAC,CACH,CAAC;YACF,MAAM,GAAG,SAAS,CAAC;YACnB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IA6CD,0BAA0B,CACxB,SAAkC;QAElC,IAAI,MAAM,GAAG,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAC3C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,iCAAiC,CAAC,SAAS,CAAC,EAAE,CAAC;gBACrE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;YACvD,CAAC;YACD,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAiCD,OAAO;QACL,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IAClC,CAAC;IAiCD,aAAa;QACX,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;IACxC,CAAC;IAiCD,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;IACvC,CAAC;IAuCD,kBAAkB;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC;IAC7C,CAAC;IAiCD,WAAW;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;IAiCD,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;IACvC,CAAC;IAiCD,WAAW;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;IA4CD,oBAAoB;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC;IAC/C,CAAC;IA8CD,0BAA0B;QAGxB,OAAO,IAAI,CAAC,SAAS,CAAC,0BAA0B,EAAE,CAAC;IACrD,CAAC;IAsCD,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;IACvC,CAAC;CACF","sourcesContent":["/** @category Validation Context */\n\nimport type { Maybe } from '../jsutils/Maybe.ts';\nimport type { ObjMap } from '../jsutils/ObjMap.ts';\n\nimport type { GraphQLError } from '../error/GraphQLError.ts';\n\nimport type {\n DocumentNode,\n FragmentDefinitionNode,\n FragmentSpreadNode,\n OperationDefinitionNode,\n SelectionSetNode,\n VariableDefinitionNode,\n VariableNode,\n} from '../language/ast.ts';\nimport { Kind } from '../language/kinds.ts';\nimport type { ASTVisitor } from '../language/visitor.ts';\nimport { visit } from '../language/visitor.ts';\n\nimport type {\n GraphQLArgument,\n GraphQLCompositeType,\n GraphQLEnumValue,\n GraphQLField,\n GraphQLInputType,\n GraphQLOutputType,\n} from '../type/definition.ts';\nimport type { GraphQLDirective } from '../type/directives.ts';\nimport type { GraphQLSchema } from '../type/schema.ts';\n\nimport type { FragmentSignature } from '../utilities/TypeInfo.ts';\nimport { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo.ts';\n\ntype NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode;\ninterface VariableUsage {\n readonly node: VariableNode;\n readonly type: Maybe<GraphQLInputType>;\n readonly parentType: Maybe<GraphQLInputType>;\n readonly defaultValue: unknown;\n readonly fragmentVariableDefinition: Maybe<VariableDefinitionNode>;\n}\n\n/**\n * An instance of this class is passed as the \"this\" context to all validators,\n * allowing access to commonly useful contextual information from within a\n * validation rule.\n *\n * @internal\n */\nexport class ASTValidationContext {\n private _ast: DocumentNode;\n private _onError: (error: GraphQLError) => void;\n private _fragments: ObjMap<FragmentDefinitionNode> | undefined;\n private _fragmentSpreads: Map<SelectionSetNode, Array<FragmentSpreadNode>>;\n private _recursivelyReferencedFragments: Map<\n OperationDefinitionNode,\n Array<FragmentDefinitionNode>\n >;\n\n constructor(ast: DocumentNode, onError: (error: GraphQLError) => void) {\n this._ast = ast;\n this._fragments = undefined;\n this._fragmentSpreads = new Map();\n this._recursivelyReferencedFragments = new Map();\n this._onError = onError;\n }\n\n get [Symbol.toStringTag](): string {\n return 'ASTValidationContext';\n }\n\n reportError(error: GraphQLError): void {\n this._onError(error);\n }\n\n getDocument(): DocumentNode {\n return this._ast;\n }\n\n getFragment(name: string): Maybe<FragmentDefinitionNode> {\n let fragments: ObjMap<FragmentDefinitionNode>;\n if (this._fragments) {\n fragments = this._fragments;\n } else {\n fragments = Object.create(null);\n for (const defNode of this.getDocument().definitions) {\n if (defNode.kind === Kind.FRAGMENT_DEFINITION) {\n fragments[defNode.name.value] = defNode;\n }\n }\n this._fragments = fragments;\n }\n return fragments[name];\n }\n\n getFragmentSpreads(\n node: SelectionSetNode,\n ): ReadonlyArray<FragmentSpreadNode> {\n let spreads = this._fragmentSpreads.get(node);\n if (!spreads) {\n spreads = [];\n const setsToVisit: Array<SelectionSetNode> = [node];\n let set: SelectionSetNode | undefined;\n while ((set = setsToVisit.pop())) {\n for (const selection of set.selections) {\n if (selection.kind === Kind.FRAGMENT_SPREAD) {\n spreads.push(selection);\n } else if (selection.selectionSet) {\n setsToVisit.push(selection.selectionSet);\n }\n }\n }\n this._fragmentSpreads.set(node, spreads);\n }\n return spreads;\n }\n\n getRecursivelyReferencedFragments(\n operation: OperationDefinitionNode,\n ): ReadonlyArray<FragmentDefinitionNode> {\n let fragments = this._recursivelyReferencedFragments.get(operation);\n if (!fragments) {\n fragments = [];\n const collectedNames = new Set<string>();\n const nodesToVisit: Array<SelectionSetNode> = [operation.selectionSet];\n let node: SelectionSetNode | undefined;\n while ((node = nodesToVisit.pop())) {\n for (const spread of this.getFragmentSpreads(node)) {\n const fragName = spread.name.value;\n if (!collectedNames.has(fragName)) {\n collectedNames.add(fragName);\n const fragment = this.getFragment(fragName);\n if (fragment) {\n fragments.push(fragment);\n nodesToVisit.push(fragment.selectionSet);\n }\n }\n }\n }\n this._recursivelyReferencedFragments.set(operation, fragments);\n }\n return fragments;\n }\n}\n\n/** @internal */\nexport type ASTValidationRule = (context: ASTValidationContext) => ASTVisitor;\n\n/** @internal */\nexport class SDLValidationContext extends ASTValidationContext {\n private _schema: Maybe<GraphQLSchema>;\n\n constructor(\n ast: DocumentNode,\n schema: Maybe<GraphQLSchema>,\n onError: (error: GraphQLError) => void,\n ) {\n super(ast, onError);\n this._schema = schema;\n }\n\n get hideSuggestions(): boolean {\n return false;\n }\n\n override get [Symbol.toStringTag](): string {\n return 'SDLValidationContext';\n }\n\n getSchema(): Maybe<GraphQLSchema> {\n return this._schema;\n }\n}\n\n/** @internal */\nexport type SDLValidationRule = (context: SDLValidationContext) => ASTVisitor;\n\n/** Validation context passed to query validation rules. */\nexport class ValidationContext extends ASTValidationContext {\n private _schema: GraphQLSchema;\n private _typeInfo: TypeInfo;\n private _variableUsages: Map<\n NodeWithSelectionSet,\n ReadonlyArray<VariableUsage>\n >;\n\n private _recursiveVariableUsages: Map<\n OperationDefinitionNode,\n ReadonlyArray<VariableUsage>\n >;\n private _hideSuggestions: boolean;\n\n /**\n * Creates a ValidationContext instance.\n * @param schema - Schema used to validate the document.\n * @param ast - Document AST being validated.\n * @param typeInfo - TypeInfo instance used to track traversal state.\n * @param onError - Callback invoked for each validation error.\n * @param hideSuggestions - Whether suggestion text should be omitted from errors.\n * @example\n * ```ts\n * import { parse } from 'graphql/language';\n * import { GraphQLError } from 'graphql/error';\n * import { buildSchema, TypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse('{ greeting }');\n * const errors = [];\n * const context = new ValidationContext(\n * schema,\n * document,\n * new TypeInfo(schema),\n * (error) => errors.push(error),\n * );\n *\n * context.reportError(new GraphQLError('Example validation error.'));\n *\n * context.getSchema(); // => schema\n * errors[0].message; // => 'Example validation error.'\n * ```\n */\n constructor(\n schema: GraphQLSchema,\n ast: DocumentNode,\n typeInfo: TypeInfo,\n onError: (error: GraphQLError) => void,\n hideSuggestions?: Maybe<boolean>,\n ) {\n super(ast, onError);\n this._schema = schema;\n this._typeInfo = typeInfo;\n this._variableUsages = new Map();\n this._recursiveVariableUsages = new Map();\n this._hideSuggestions = hideSuggestions ?? false;\n }\n\n /**\n * Returns the value used by `Object.prototype.toString`.\n * @returns The built-in string tag for this object.\n */\n override get [Symbol.toStringTag](): string {\n return 'ValidationContext';\n }\n\n /**\n * Returns whether validation error suggestions are hidden.\n * @returns True when suggestion text should be omitted from errors.\n */\n get hideSuggestions(): boolean {\n return this._hideSuggestions;\n }\n\n /**\n * Returns the schema being used by this validation context.\n * @returns The schema being validated against.\n * @example\n * ```ts\n * import { parse } from 'graphql/language';\n * import { buildSchema, TypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const context = new ValidationContext(\n * schema,\n * parse('{ greeting }'),\n * new TypeInfo(schema),\n * () => {},\n * );\n *\n * context.getSchema().getQueryType()?.name; // => 'Query'\n * ```\n */\n getSchema(): GraphQLSchema {\n return this._schema;\n }\n\n /**\n * Returns variable usages found directly within this node.\n * @param node - The AST node to inspect or visit.\n * @returns Variable usages found directly within this node.\n * @example\n * ```ts\n * import { parse } from 'graphql/language';\n * import { buildSchema, TypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting(name: String): String\n * }\n * `);\n * const document = parse('query ($name: String) { greeting(name: $name) }');\n * const operation = document.definitions[0];\n * const context = new ValidationContext(\n * schema,\n * document,\n * new TypeInfo(schema),\n * () => {},\n * );\n *\n * const usages = context.getVariableUsages(operation);\n *\n * usages[0].node.name.value; // => 'name'\n * String(usages[0].type); // => 'String'\n * ```\n */\n getVariableUsages(node: NodeWithSelectionSet): ReadonlyArray<VariableUsage> {\n let usages = this._variableUsages.get(node);\n if (!usages) {\n const newUsages: Array<VariableUsage> = [];\n const typeInfo = new TypeInfo(\n this._schema,\n undefined,\n this._typeInfo.getFragmentSignatureByName(),\n );\n const fragmentDefinition =\n node.kind === Kind.FRAGMENT_DEFINITION ? node : undefined;\n visit(\n node,\n visitWithTypeInfo(typeInfo, {\n VariableDefinition: () => false,\n Variable(variable) {\n let fragmentVariableDefinition;\n if (fragmentDefinition) {\n const fragmentSignature = typeInfo.getFragmentSignatureByName()(\n fragmentDefinition.name.value,\n );\n\n fragmentVariableDefinition =\n fragmentSignature?.variableDefinitions.get(variable.name.value);\n newUsages.push({\n node: variable,\n type: typeInfo.getInputType(),\n parentType: typeInfo.getParentInputType(),\n defaultValue: undefined, // fragment variables have a variable default but no location default, which is what this default value represents\n fragmentVariableDefinition,\n });\n } else {\n newUsages.push({\n node: variable,\n type: typeInfo.getInputType(),\n parentType: typeInfo.getParentInputType(),\n defaultValue: typeInfo.getDefaultValue(),\n fragmentVariableDefinition: undefined,\n });\n }\n },\n }),\n );\n usages = newUsages;\n this._variableUsages.set(node, usages);\n }\n return usages;\n }\n\n /**\n * Returns variable usages for an operation, including variables used by referenced fragments.\n * @param operation - Operation definition to inspect.\n * @returns Variable usages reachable from the operation.\n * @example\n * ```ts\n * import { parse } from 'graphql/language';\n * import { buildSchema, TypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * viewer: User\n * }\n *\n * type User {\n * name(prefix: String): String\n * }\n * `);\n * const document = parse(`\n * query ($prefix: String) {\n * viewer {\n * ...UserName\n * }\n * }\n *\n * fragment UserName on User {\n * name(prefix: $prefix)\n * }\n * `);\n * const operation = document.definitions[0];\n * const context = new ValidationContext(\n * schema,\n * document,\n * new TypeInfo(schema),\n * () => {},\n * );\n *\n * const usages = context.getRecursiveVariableUsages(operation);\n *\n * usages.map((usage) => usage.node.name.value); // => ['prefix']\n * ```\n */\n getRecursiveVariableUsages(\n operation: OperationDefinitionNode,\n ): ReadonlyArray<VariableUsage> {\n let usages = this._recursiveVariableUsages.get(operation);\n if (!usages) {\n usages = this.getVariableUsages(operation);\n for (const frag of this.getRecursivelyReferencedFragments(operation)) {\n usages = usages.concat(this.getVariableUsages(frag));\n }\n this._recursiveVariableUsages.set(operation, usages);\n }\n return usages;\n }\n\n /**\n * Returns the current output type at this point in traversal.\n * @returns The current output type, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse('{ greeting }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let typeName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Field: () => {\n * typeName = String(context.getType());\n * },\n * }),\n * );\n *\n * typeName; // => 'String'\n * ```\n */\n getType(): Maybe<GraphQLOutputType> {\n return this._typeInfo.getType();\n }\n\n /**\n * Returns the current parent composite type.\n * @returns The current parent composite type, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse('{ greeting }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let parentTypeName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Field: () => {\n * parentTypeName = context.getParentType()?.name;\n * },\n * }),\n * );\n *\n * parentTypeName; // => 'Query'\n * ```\n */\n getParentType(): Maybe<GraphQLCompositeType> {\n return this._typeInfo.getParentType();\n }\n\n /**\n * Returns the current input type at this point in traversal.\n * @returns The current input type, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * reviews(limit: Int): [String]\n * }\n * `);\n * const document = parse('{ reviews(limit: 5) }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let inputTypeName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Argument: () => {\n * inputTypeName = String(context.getInputType());\n * },\n * }),\n * );\n *\n * inputTypeName; // => 'Int'\n * ```\n */\n getInputType(): Maybe<GraphQLInputType> {\n return this._typeInfo.getInputType();\n }\n\n // Note: continues to expose the closest enclosing valid input type if\n // traversal descends into syntax with no corresponding GraphQL input type.\n /**\n * Returns the parent input type for the current input position.\n * @returns The parent input type, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * input ReviewFilter {\n * stars: Int\n * }\n *\n * type Query {\n * reviews(filter: ReviewFilter): [String]\n * }\n * `);\n * const document = parse('{ reviews(filter: { stars: 5 }) }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let parentInputTypeName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * ObjectField: () => {\n * parentInputTypeName = String(context.getParentInputType());\n * },\n * }),\n * );\n *\n * parentInputTypeName; // => 'ReviewFilter'\n * ```\n */\n getParentInputType(): Maybe<GraphQLInputType> {\n return this._typeInfo.getParentInputType();\n }\n\n /**\n * Returns the current field definition.\n * @returns The current field definition, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse('{ greeting }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let fieldName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Field: () => {\n * fieldName = context.getFieldDef()?.name;\n * },\n * }),\n * );\n *\n * fieldName; // => 'greeting'\n * ```\n */\n getFieldDef(): Maybe<GraphQLField<unknown, unknown>> {\n return this._typeInfo.getFieldDef();\n }\n\n /**\n * Returns the current directive definition.\n * @returns The current directive definition, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse('{ greeting @include(if: true) }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let directiveName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Directive: () => {\n * directiveName = context.getDirective()?.name;\n * },\n * }),\n * );\n *\n * directiveName; // => 'include'\n * ```\n */\n getDirective(): Maybe<GraphQLDirective> {\n return this._typeInfo.getDirective();\n }\n\n /**\n * Returns the current argument definition.\n * @returns The current argument definition, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * reviews(limit: Int): [String]\n * }\n * `);\n * const document = parse('{ reviews(limit: 5) }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let argumentName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Argument: () => {\n * argumentName = context.getArgument()?.name;\n * },\n * }),\n * );\n *\n * argumentName; // => 'limit'\n * ```\n */\n getArgument(): Maybe<GraphQLArgument> {\n return this._typeInfo.getArgument();\n }\n\n /**\n * Returns the fragment signature at the current traversal position.\n * @returns The current fragment signature, if one is active.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse(\n * `\n * {\n * ...GreetingFields\n * }\n *\n * fragment GreetingFields on Query {\n * greeting\n * }\n * `,\n * { experimentalFragmentArguments: true },\n * );\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let fragmentName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * FragmentSpread: () => {\n * fragmentName = context.getFragmentSignature()?.definition.name.value;\n * },\n * }),\n * );\n *\n * fragmentName; // => 'GreetingFields'\n * ```\n */\n getFragmentSignature(): Maybe<FragmentSignature> {\n return this._typeInfo.getFragmentSignature();\n }\n\n /**\n * Returns the function used to look up fragment signatures by name.\n * @returns A function that maps fragment names to fragment signatures.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse(\n * `\n * {\n * ...GreetingFields\n * }\n *\n * fragment GreetingFields on Query {\n * greeting\n * }\n * `,\n * { experimentalFragmentArguments: true },\n * );\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let fragmentName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * Document: () => {\n * const getFragmentSignature = context.getFragmentSignatureByName();\n * fragmentName =\n * getFragmentSignature('GreetingFields')?.definition.name.value;\n * },\n * }),\n * );\n *\n * fragmentName; // => 'GreetingFields'\n * ```\n */\n getFragmentSignatureByName(): (\n fragmentName: string,\n ) => Maybe<FragmentSignature> {\n return this._typeInfo.getFragmentSignatureByName();\n }\n\n /**\n * Returns the current enum value definition.\n * @returns The current enum value definition, if known.\n * @example\n * ```ts\n * import { parse, visit } from 'graphql/language';\n * import { buildSchema, TypeInfo, visitWithTypeInfo } from 'graphql/utilities';\n * import { ValidationContext } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * enum Sort {\n * NEWEST\n * OLDEST\n * }\n *\n * type Query {\n * reviews(sort: Sort): [String]\n * }\n * `);\n * const document = parse('{ reviews(sort: OLDEST) }');\n * const typeInfo = new TypeInfo(schema);\n * const context = new ValidationContext(schema, document, typeInfo, () => {});\n * let enumValueName;\n *\n * visit(\n * document,\n * visitWithTypeInfo(typeInfo, {\n * EnumValue: () => {\n * enumValueName = context.getEnumValue()?.name;\n * },\n * }),\n * );\n *\n * enumValueName; // => 'OLDEST'\n * ```\n */\n getEnumValue(): Maybe<GraphQLEnumValue> {\n return this._typeInfo.getEnumValue();\n }\n}\n\n/** A function that creates an AST visitor for validating a GraphQL document. */\nexport type ValidationRule = (context: ValidationContext) => ASTVisitor;\n"]}