{"version":3,"file":"DeferStreamDirectiveOnRootFieldRule.js","sourceRoot":"","sources":["../../../src/validation/rules/DeferStreamDirectiveOnRootFieldRule.ts"],"names":[],"mappings":"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","sourcesContent":["/** @category Validation Rules */\n\nimport { GraphQLError } from '../../error/GraphQLError.ts';\n\nimport type {\n  FragmentDefinitionNode,\n  FragmentSpreadNode,\n  InlineFragmentNode,\n  OperationDefinitionNode,\n  OperationTypeNode,\n  SelectionSetNode,\n} from '../../language/ast.ts';\nimport { Kind } from '../../language/kinds.ts';\nimport type { ASTVisitor } from '../../language/visitor.ts';\n\nimport type { GraphQLObjectType } from '../../type/definition.ts';\nimport {\n  GraphQLDeferDirective,\n  GraphQLStreamDirective,\n} from '../../type/directives.ts';\n\nimport type { ValidationContext } from '../ValidationContext.ts';\n\n/**\n * Defer and stream directives are used on valid root field\n *\n * A GraphQL document is only valid if defer directives are not used on root mutation or subscription types.\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 { parse } from 'graphql/language';\n * import { buildSchema } from 'graphql/utilities';\n * import {\n *   validate,\n *   DeferStreamDirectiveOnRootFieldRule,\n * } from 'graphql/validation';\n *\n * const schema = buildSchema(`\n *   type Query {\n *     message: String\n *   }\n *\n *   type Mutation {\n *     updateMessage: String\n *   }\n * `);\n * const invalidDocument = parse(`\n *   mutation { ... @defer { updateMessage } }\n * `);\n * const validDocument = parse(`\n *   { ... @defer { message } }\n * `);\n *\n * validate(schema, invalidDocument, [DeferStreamDirectiveOnRootFieldRule]).length; // => 1\n * validate(schema, validDocument, [DeferStreamDirectiveOnRootFieldRule]); // => []\n * ```\n */\nexport function DeferStreamDirectiveOnRootFieldRule(\n  context: ValidationContext,\n): ASTVisitor {\n  return {\n    OperationDefinition(node: OperationDefinitionNode) {\n      const document = context.getDocument();\n      const fragments = new Map<string, FragmentDefinitionNode>();\n\n      for (const definition of document.definitions) {\n        if (definition.kind === Kind.FRAGMENT_DEFINITION) {\n          fragments.set(definition.name.value, definition);\n        }\n      }\n      if (node.operation !== 'subscription' && node.operation !== 'mutation') {\n        return;\n      }\n      const schema = context.getSchema();\n      const rootType = schema.getRootType(node.operation);\n      if (rootType) {\n        forbidDeferStream({\n          context,\n          operationType: node.operation,\n          rootType,\n          fragments,\n          selectionSet: node.selectionSet,\n          visitedFragments: new Set(),\n        });\n      }\n    },\n  };\n}\n\nfunction forbidDeferStream({\n  context,\n  operationType,\n  rootType,\n  fragments,\n  selectionSet,\n  visitedFragments,\n}: {\n  context: ValidationContext;\n  operationType: OperationTypeNode;\n  rootType: GraphQLObjectType;\n  fragments: Map<string, FragmentDefinitionNode>;\n  selectionSet: SelectionSetNode;\n  visitedFragments: Set<string>;\n}) {\n  for (const selection of selectionSet.selections) {\n    if (selection.kind === 'Field') {\n      const stream = selection.directives?.find(\n        (d) => d.name.value === GraphQLStreamDirective.name,\n      );\n      if (stream) {\n        context.reportError(\n          new GraphQLError(\n            `Stream directive cannot be used on root ${operationType} type \"${rootType}\".`,\n            { nodes: stream },\n          ),\n        );\n      }\n    } else if (selection.kind === 'FragmentSpread') {\n      const fragmentName = selection.name.value;\n      if (visitedFragments.has(fragmentName)) {\n        continue;\n      }\n      const fragment = fragments.get(fragmentName);\n      if (fragment) {\n        const defer = getDeferDirective(selection);\n        if (defer !== undefined) {\n          context.reportError(\n            new GraphQLError(\n              `Defer directive cannot be used on root ${operationType} type \"${rootType}\".`,\n              { nodes: defer },\n            ),\n          );\n        }\n        forbidDeferStream({\n          context,\n          operationType,\n          rootType,\n          fragments,\n          selectionSet: fragment.selectionSet,\n          visitedFragments,\n        });\n      }\n      visitedFragments.add(fragmentName);\n    } else if (selection.kind === 'InlineFragment') {\n      const defer = getDeferDirective(selection);\n      if (defer !== undefined) {\n        context.reportError(\n          new GraphQLError(\n            `Defer directive cannot be used on root ${operationType} type \"${rootType}\".`,\n            { nodes: defer },\n          ),\n        );\n      }\n      forbidDeferStream({\n        context,\n        operationType,\n        rootType,\n        fragments,\n        selectionSet: selection.selectionSet,\n        visitedFragments,\n      });\n    }\n  }\n}\n\nfunction getDeferDirective(fragment: FragmentSpreadNode | InlineFragmentNode) {\n  return fragment.directives?.find(\n    (d) => d.name.value === GraphQLDeferDirective.name,\n  );\n}\n"]}