{"version":3,"file":"SingleFieldSubscriptionsRule.js","sourceRoot":"","sources":["../../../src/validation/rules/SingleFieldSubscriptionsRule.ts"],"names":[],"mappings":"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","sourcesContent":["/** @category Validation Rules */\n\nimport type { ObjMap } from '../../jsutils/ObjMap.ts';\n\nimport { GraphQLError } from '../../error/GraphQLError.ts';\n\nimport type { FieldNode, OperationDefinitionNode } from '../../language/ast.ts';\nimport { Kind } from '../../language/kinds.ts';\nimport type { ASTVisitor } from '../../language/visitor.ts';\n\nimport type {\n  FieldDetailsList,\n  FragmentDetails,\n} from '../../execution/collectFields.ts';\nimport { collectFields } from '../../execution/collectFields.ts';\nimport type { VariableValues } from '../../execution/values.ts';\n\nimport type { ValidationContext } from '../ValidationContext.ts';\n\nfunction toNodes(fieldDetailsList: FieldDetailsList): ReadonlyArray<FieldNode> {\n  return fieldDetailsList.map((fieldDetails) => fieldDetails.node);\n}\n\n/**\n * Subscriptions must only include a non-introspection field.\n *\n * A GraphQL subscription is valid only if it contains a single root field and\n * that root field is not an introspection field.\n *\n * See https://spec.graphql.org/draft/#sec-Single-root-field\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 { SingleFieldSubscriptionsRule } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n *   type Query {\n *     name: String\n *   }\n *\n *   type Subscription {\n *     a: String\n *     b: String\n *   }\n * `);\n *\n * const invalidDocument = parse(`\n *   subscription { a b }\n * `);\n * const invalidErrors = validate(schema, invalidDocument, [\n *   SingleFieldSubscriptionsRule,\n * ]);\n *\n * invalidErrors.length; // => 1\n *\n * const validDocument = parse(`\n *   subscription { a }\n * `);\n * const validErrors = validate(schema, validDocument, [\n *   SingleFieldSubscriptionsRule,\n * ]);\n *\n * validErrors; // => []\n * ```\n */\nexport function SingleFieldSubscriptionsRule(\n  context: ValidationContext,\n): ASTVisitor {\n  return {\n    OperationDefinition(node: OperationDefinitionNode) {\n      if (node.operation === 'subscription') {\n        const schema = context.getSchema();\n        const subscriptionType = schema.getSubscriptionType();\n        if (subscriptionType) {\n          const operationName = node.name ? node.name.value : null;\n          const variableValues: VariableValues = Object.create(null);\n          const document = context.getDocument();\n          const fragments: ObjMap<FragmentDetails> = Object.create(null);\n          for (const definition of document.definitions) {\n            if (definition.kind === Kind.FRAGMENT_DEFINITION) {\n              fragments[definition.name.value] = { definition };\n            }\n          }\n          const { groupedFieldSet, forbiddenDirectiveInstances } =\n            collectFields(\n              schema,\n              fragments,\n              variableValues,\n              subscriptionType,\n              node.selectionSet,\n              context.hideSuggestions,\n              true,\n            );\n          if (forbiddenDirectiveInstances.length > 0) {\n            context.reportError(\n              new GraphQLError(\n                operationName != null\n                  ? `Subscription \"${operationName}\" must not use \\`@skip\\` or \\`@include\\` directives in the top level selection.`\n                  : 'Anonymous Subscription must not use `@skip` or `@include` directives in the top level selection.',\n                { nodes: forbiddenDirectiveInstances },\n              ),\n            );\n            return;\n          }\n          if (groupedFieldSet.size > 1) {\n            const fieldDetailsLists = [...groupedFieldSet.values()];\n            const extraFieldDetailsLists = fieldDetailsLists.slice(1);\n            const extraFieldSelections = extraFieldDetailsLists.flatMap(\n              (fieldDetailsList) => toNodes(fieldDetailsList),\n            );\n            context.reportError(\n              new GraphQLError(\n                operationName != null\n                  ? `Subscription \"${operationName}\" must select only one top level field.`\n                  : 'Anonymous Subscription must select only one top level field.',\n                { nodes: extraFieldSelections },\n              ),\n            );\n          }\n          for (const fieldDetailsList of groupedFieldSet.values()) {\n            const fieldName = toNodes(fieldDetailsList)[0].name.value;\n            if (fieldName.startsWith('__')) {\n              context.reportError(\n                new GraphQLError(\n                  operationName != null\n                    ? `Subscription \"${operationName}\" must not select an introspection top level field.`\n                    : 'Anonymous Subscription must not select an introspection top level field.',\n                  { nodes: toNodes(fieldDetailsList) },\n                ),\n              );\n            }\n          }\n        }\n      }\n    },\n  };\n}\n"]}