graphql
Version:
A Query Language and Runtime which can target any service.
1 lines • 9.9 kB
Source Map (JSON)
{"version":3,"file":"ProvidedRequiredArgumentsRule.js","sourceRoot":"","sources":["../../../src/validation/rules/ProvidedRequiredArgumentsRule.ts"],"names":[],"mappings":"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","sourcesContent":["/** @category Validation Rules */\n\nimport { inspect } from '../../jsutils/inspect.ts';\n\nimport { GraphQLError } from '../../error/GraphQLError.ts';\n\nimport type {\n InputValueDefinitionNode,\n VariableDefinitionNode,\n} from '../../language/ast.ts';\nimport { Kind } from '../../language/kinds.ts';\nimport { print } from '../../language/printer.ts';\nimport type { ASTVisitor } from '../../language/visitor.ts';\n\nimport type { GraphQLArgument } from '../../type/definition.ts';\nimport { isRequiredArgument, isType } from '../../type/definition.ts';\nimport { specifiedDirectives } from '../../type/directives.ts';\n\nimport { typeFromAST } from '../../utilities/typeFromAST.ts';\n\nimport type {\n SDLValidationContext,\n ValidationContext,\n} from '../ValidationContext.ts';\n\n/**\n * Provided required arguments\n *\n * A field or directive is only valid if all required (non-null without a\n * default value) field arguments have been provided.\n * @param context - The validation context used while checking the document.\n * @returns A visitor that reports validation errors for this rule.\n * @example\n * ```ts\n * import { buildSchema, parse, validate } from 'graphql';\n * import { ProvidedRequiredArgumentsRule } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * field(required: String!): String\n * }\n * `);\n *\n * const invalidDocument = parse(`\n * { field }\n * `);\n * const invalidErrors = validate(schema, invalidDocument, [\n * ProvidedRequiredArgumentsRule,\n * ]);\n *\n * invalidErrors.length; // => 1\n *\n * const validDocument = parse(`\n * { field(required: \"x\") }\n * `);\n * const validErrors = validate(schema, validDocument, [\n * ProvidedRequiredArgumentsRule,\n * ]);\n *\n * validErrors; // => []\n * ```\n */\nexport function ProvidedRequiredArgumentsRule(\n context: ValidationContext,\n): ASTVisitor {\n return {\n // eslint-disable-next-line new-cap\n ...ProvidedRequiredArgumentsOnDirectivesRule(context),\n Field: {\n // Validate on leave to allow for deeper errors to appear first.\n leave(fieldNode) {\n const fieldDef = context.getFieldDef();\n if (!fieldDef) {\n return false;\n }\n\n const providedArgs = new Set(\n fieldNode.arguments?.map((arg) => arg.name.value),\n );\n for (const argDef of fieldDef.args) {\n if (!providedArgs.has(argDef.name) && isRequiredArgument(argDef)) {\n context.reportError(\n new GraphQLError(\n `Argument \"${argDef}\" of type \"${argDef.type}\" is required, but it was not provided.`,\n { nodes: fieldNode },\n ),\n );\n }\n }\n },\n },\n FragmentSpread: {\n // Validate on leave to allow for deeper errors to appear first.\n leave(spreadNode) {\n const fragmentSignature = context.getFragmentSignature();\n if (!fragmentSignature) {\n return false;\n }\n\n const providedArgs = new Set(\n spreadNode.arguments?.map((arg) => arg.name.value),\n );\n for (const [\n varName,\n variableDefinition,\n ] of fragmentSignature.variableDefinitions) {\n if (\n !providedArgs.has(varName) &&\n isRequiredArgumentNode(variableDefinition)\n ) {\n const type = typeFromAST(\n context.getSchema(),\n variableDefinition.type,\n );\n const argTypeStr = inspect(type);\n context.reportError(\n new GraphQLError(\n `Fragment \"${spreadNode.name.value}\" argument \"${varName}\" of type \"${argTypeStr}\" is required, but it was not provided.`,\n { nodes: spreadNode },\n ),\n );\n }\n }\n },\n },\n };\n}\n\n/** @internal */\nexport function ProvidedRequiredArgumentsOnDirectivesRule(\n context: ValidationContext | SDLValidationContext,\n): ASTVisitor {\n const requiredArgsMap = new Map<\n string,\n Map<string, GraphQLArgument | InputValueDefinitionNode>\n >();\n\n const schema = context.getSchema();\n const definedDirectives = schema?.getDirectives() ?? specifiedDirectives;\n for (const directive of definedDirectives) {\n requiredArgsMap.set(\n directive.name,\n new Map(\n directive.args.filter(isRequiredArgument).map((arg) => [arg.name, arg]),\n ),\n );\n }\n\n const astDefinitions = context.getDocument().definitions;\n for (const def of astDefinitions) {\n if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n const argNodes = def.arguments ?? [];\n\n requiredArgsMap.set(\n def.name.value,\n new Map(\n argNodes\n .filter(isRequiredArgumentNode)\n .map((arg) => [arg.name.value, arg]),\n ),\n );\n }\n }\n\n return {\n Directive: {\n // Validate on leave to allow for deeper errors to appear first.\n leave(directiveNode) {\n const directiveName = directiveNode.name.value;\n const requiredArgs = requiredArgsMap.get(directiveName);\n if (requiredArgs != null) {\n const argNodes = directiveNode.arguments ?? [];\n const argNodeMap = new Set(argNodes.map((arg) => arg.name.value));\n for (const [argName, argDef] of requiredArgs.entries()) {\n if (!argNodeMap.has(argName)) {\n const argType = isType(argDef.type)\n ? inspect(argDef.type)\n : print(argDef.type);\n context.reportError(\n new GraphQLError(\n `Argument \"@${directiveName}(${argName}:)\" of type \"${argType}\" is required, but it was not provided.`,\n { nodes: directiveNode },\n ),\n );\n }\n }\n }\n },\n },\n };\n}\n\nfunction isRequiredArgumentNode(\n arg: InputValueDefinitionNode | VariableDefinitionNode,\n): boolean {\n return arg.type.kind === Kind.NON_NULL_TYPE && arg.defaultValue == null;\n}\n"]}