graphql
Version:
A Query Language and Runtime which can target any service.
1 lines • 10.3 kB
Source Map (JSON)
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/validation/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/** @category Validation */\n\nimport { mapValue } from '../jsutils/mapValue.ts';\nimport type { Maybe } from '../jsutils/Maybe.ts';\n\nimport { GraphQLError } from '../error/GraphQLError.ts';\n\nimport type { DocumentNode } from '../language/ast.ts';\nimport { QueryDocumentKeys } from '../language/ast.ts';\nimport { visit, visitInParallel } from '../language/visitor.ts';\n\nimport type { GraphQLSchema } from '../type/schema.ts';\nimport { assertValidSchema } from '../type/validate.ts';\n\nimport { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo.ts';\n\nimport { shouldTrace, validateChannel } from '../diagnostics.ts';\n\nimport { specifiedRules, specifiedSDLRules } from './specifiedRules.ts';\nimport type { SDLValidationRule, ValidationRule } from './ValidationContext.ts';\nimport {\n SDLValidationContext,\n ValidationContext,\n} from './ValidationContext.ts';\n\n/**\n * Options used when validating a GraphQL document.\n * @category Validation\n */\nexport interface ValidationOptions {\n /** Maximum number of validation errors before validation stops. */\n maxErrors?: number;\n /** Whether suggestion text should be omitted from validation errors. */\n hideSuggestions?: Maybe<boolean>;\n}\n\n// Per the specification, descriptions must not affect validation.\n// See https://spec.graphql.org/draft/#sec-Descriptions\nconst QueryDocumentKeysToValidate = mapValue(\n QueryDocumentKeys,\n (keys: ReadonlyArray<string>) => keys.filter((key) => key !== 'description'),\n);\n\nconst tooManyValidationErrorsError = new GraphQLError(\n 'Too many validation errors, error limit reached. Validation aborted.',\n);\n\n/**\n * Implements the \"Validation\" section of the spec.\n *\n * Validation runs synchronously, returning an array of encountered errors, or\n * an empty array if no errors were encountered and the document is valid.\n *\n * A list of specific validation rules may be provided. If not provided, the\n * default list of rules defined by the GraphQL specification will be used.\n *\n * Each validation rule is a function that returns a visitor\n * (see the language/visitor API). Visitor methods are expected to return\n * GraphQLErrors, or Arrays of GraphQLErrors when invalid.\n *\n * Validate will stop validation after a `maxErrors` limit has been reached.\n * Attackers can send pathologically invalid queries to induce a DoS attack,\n * so `maxErrors` defaults to 100 errors.\n * @param schema - Schema to validate against.\n * @param documentAST - Document AST to validate.\n * @param rules - Validation rules to apply.\n * @param options - Validation options, including error limits and suggestions.\n * @returns Validation errors, or an empty array when the document is valid.\n * @example\n * ```ts\n * // Validate with the default specified rules.\n * import { parse } from 'graphql/language';\n * import { buildSchema } from 'graphql/utilities';\n * import { validate } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * fullName: String\n * }\n * `);\n *\n * validate(schema, parse('{ greeting }')); // => []\n *\n * const errors = validate(schema, parse('{ missing }'));\n * errors[0].message; // => 'Cannot query field \"missing\" on type \"Query\".'\n * ```\n * @example\n * ```ts\n * // This variant uses a custom rule list and validation options.\n * import { parse } from 'graphql/language';\n * import { buildSchema } from 'graphql/utilities';\n * import { FieldsOnCorrectTypeRule, validate } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n * type Query {\n * greeting: String\n * }\n * `);\n * const document = parse('{ missingOne missingTwo }');\n *\n * const errors = validate(schema, document, [FieldsOnCorrectTypeRule], {\n * maxErrors: 1,\n * });\n *\n * errors.length; // => 2\n * errors[1].message; // => 'Too many validation errors, error limit reached. Validation aborted.'\n *\n * const hiddenSuggestionErrors = validate(\n * schema,\n * parse('{ name }'),\n * [FieldsOnCorrectTypeRule],\n * { hideSuggestions: true },\n * );\n *\n * hiddenSuggestionErrors[0].message; // => 'Cannot query field \"name\" on type \"Query\".'\n * ```\n */\nexport function validate(\n schema: GraphQLSchema,\n documentAST: DocumentNode,\n rules: ReadonlyArray<ValidationRule> = specifiedRules,\n options?: ValidationOptions,\n): ReadonlyArray<GraphQLError> {\n return shouldTrace(validateChannel)\n ? validateChannel.traceSync(\n () => validateImpl(schema, documentAST, rules, options),\n { schema, document: documentAST },\n )\n : validateImpl(schema, documentAST, rules, options);\n}\n\nfunction validateImpl(\n schema: GraphQLSchema,\n documentAST: DocumentNode,\n rules: ReadonlyArray<ValidationRule>,\n options: ValidationOptions | undefined,\n): ReadonlyArray<GraphQLError> {\n const maxErrors = options?.maxErrors ?? 100;\n const hideSuggestions = options?.hideSuggestions ?? false;\n\n // If the schema used for validation is invalid, throw an error.\n assertValidSchema(schema);\n\n const errors: Array<GraphQLError> = [];\n const typeInfo = new TypeInfo(schema);\n const context = new ValidationContext(\n schema,\n documentAST,\n typeInfo,\n (error) => {\n if (errors.length >= maxErrors) {\n throw tooManyValidationErrorsError;\n }\n errors.push(error);\n },\n hideSuggestions,\n );\n\n // This uses a specialized visitor which runs multiple visitors in parallel,\n // while maintaining the visitor skip and break API.\n const visitor = visitInParallel(rules.map((rule) => rule(context)));\n\n // Visit the whole document with each instance of all provided rules.\n try {\n visit(\n documentAST,\n visitWithTypeInfo(typeInfo, visitor),\n QueryDocumentKeysToValidate,\n );\n } catch (e: unknown) {\n if (e === tooManyValidationErrorsError) {\n errors.push(tooManyValidationErrorsError);\n } else {\n throw e;\n }\n }\n return errors;\n}\n\n/** @internal */\nexport function validateSDL(\n documentAST: DocumentNode,\n schemaToExtend?: Maybe<GraphQLSchema>,\n rules: ReadonlyArray<SDLValidationRule> = specifiedSDLRules,\n): ReadonlyArray<GraphQLError> {\n const errors: Array<GraphQLError> = [];\n const context = new SDLValidationContext(\n documentAST,\n schemaToExtend,\n (error) => {\n errors.push(error);\n },\n );\n\n const visitors = rules.map((rule) => rule(context));\n visit(documentAST, visitInParallel(visitors));\n return errors;\n}\n\n/**\n * Utility function which asserts a SDL document is valid by throwing an error\n * if it is invalid.\n *\n * @internal\n */\nexport function assertValidSDL(documentAST: DocumentNode): void {\n const errors = validateSDL(documentAST);\n if (errors.length !== 0) {\n throw new Error(errors.map((error) => error.message).join('\\n\\n'));\n }\n}\n\n/**\n * Utility function which asserts a SDL document is valid by throwing an error\n * if it is invalid.\n *\n * @internal\n */\nexport function assertValidSDLExtension(\n documentAST: DocumentNode,\n schema: GraphQLSchema,\n): void {\n const errors = validateSDL(documentAST, schema);\n if (errors.length !== 0) {\n throw new Error(errors.map((error) => error.message).join('\\n\\n'));\n }\n}\n"]}