OperationValidationRule.java

package graphql.validation;

import graphql.PublicApi;
import org.jspecify.annotations.NullMarked;

/**
 * Enumerates the individual validation rules that can be applied to a GraphQL operation document.
 * Each value corresponds to a validation rule defined in the GraphQL specification.
 *
 * <p>This enum is used with {@link OperationValidator} to selectively enable or disable
 * individual validation rules via a {@code Predicate<OperationValidationRule>}.
 *
 * <h2>Rule Categories by Traversal Behavior</h2>
 *
 * <p>The {@link OperationValidator} tracks two independent state variables during traversal:
 * {@code fragmentRetraversalDepth} (0 = primary traversal, >0 = inside fragment retraversal)
 * and {@code operationScope} (true = inside an operation, false = outside).
 *
 * <p>This creates three possible traversal states:
 * <pre>
 * ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
 * ��� State                              ��� When                                             ���
 * ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
 * ��� depth=0, operationScope=false      ��� Fragment definitions at document level           ���
 * ��� depth=0, operationScope=true       ��� Nodes directly inside an operation               ���
 * ��� depth>0, operationScope=true       ��� Nodes inside fragments reached via spread        ���
 * ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
 * </pre>
 *
 * <p>Rules are categorized by which states they run in:
 * <pre>
 * ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
 * ��� Rule Category        ��� depth=0              ��� depth=0             ��� depth>0             ���
 * ���                      ��� operationScope=false ��� operationScope=true ��� operationScope=true ���
 * ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
 * ��� Document-Level Rules ���         RUN          ���         RUN         ���        SKIP         ���
 * ��� Operation-Scoped     ���        SKIP          ���         RUN         ���         RUN         ���
 * ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
 * </pre>
 *
 * <h3>Document-Level Rules</h3>
 * <p>Condition: {@code fragmentRetraversalDepth == 0}
 * <p>Validates each AST node exactly once during primary traversal. Skips during fragment
 * retraversal to avoid duplicate errors (fragments are validated at document level).
 * <ul>
 *   <li>{@link #EXECUTABLE_DEFINITIONS} - only executable definitions allowed</li>
 *   <li>{@link #ARGUMENTS_OF_CORRECT_TYPE} - argument values match declared types</li>
 *   <li>{@link #FIELDS_ON_CORRECT_TYPE} - fields exist on parent type</li>
 *   <li>{@link #FRAGMENTS_ON_COMPOSITE_TYPE} - fragments on object/interface/union types</li>
 *   <li>{@link #KNOWN_ARGUMENT_NAMES} - arguments are defined on field/directive</li>
 *   <li>{@link #KNOWN_DIRECTIVES} - directives are defined in schema</li>
 *   <li>{@link #KNOWN_FRAGMENT_NAMES} - fragment spreads reference defined fragments</li>
 *   <li>{@link #KNOWN_TYPE_NAMES} - type references exist in schema</li>
 *   <li>{@link #NO_FRAGMENT_CYCLES} - fragments do not form cycles</li>
 *   <li>{@link #NO_UNUSED_FRAGMENTS} - all fragments are used by operations</li>
 *   <li>{@link #OVERLAPPING_FIELDS_CAN_BE_MERGED} - fields with same response key are mergeable</li>
 *   <li>{@link #POSSIBLE_FRAGMENT_SPREADS} - fragment type conditions overlap with parent</li>
 *   <li>{@link #PROVIDED_NON_NULL_ARGUMENTS} - required arguments are provided</li>
 *   <li>{@link #SCALAR_LEAVES} - scalar fields have no subselections, composites require them</li>
 *   <li>{@link #VARIABLE_DEFAULT_VALUES_OF_CORRECT_TYPE} - variable defaults match type</li>
 *   <li>{@link #VARIABLES_ARE_INPUT_TYPES} - variables use input types only</li>
 *   <li>{@link #LONE_ANONYMOUS_OPERATION} - anonymous operations are alone in document</li>
 *   <li>{@link #UNIQUE_OPERATION_NAMES} - operation names are unique</li>
 *   <li>{@link #UNIQUE_FRAGMENT_NAMES} - fragment names are unique</li>
 *   <li>{@link #UNIQUE_DIRECTIVE_NAMES_PER_LOCATION} - non-repeatable directives appear once</li>
 *   <li>{@link #UNIQUE_ARGUMENT_NAMES} - argument names are unique per field/directive</li>
 *   <li>{@link #UNIQUE_VARIABLE_NAMES} - variable names are unique per operation</li>
 *   <li>{@link #SUBSCRIPTION_UNIQUE_ROOT_FIELD} - subscriptions have single root field</li>
 *   <li>{@link #UNIQUE_OBJECT_FIELD_NAME} - input object fields are unique</li>
 *   <li>{@link #DEFER_DIRECTIVE_LABEL} - defer labels are unique strings</li>
 *   <li>{@link #KNOWN_OPERATION_TYPES} - schema supports the operation type</li>
 * </ul>
 *
 * <h3>Operation-Scoped Rules</h3>
 * <p>Condition: {@code operationScope == true}
 * <p>Tracks state across an entire operation, following fragment spreads to see all code paths.
 * Skips outside operations (e.g., fragment definitions at document level) where there is no
 * operation context to validate against.
 * <ul>
 *   <li>{@link #NO_UNDEFINED_VARIABLES} - all variable references are defined in operation</li>
 *   <li>{@link #NO_UNUSED_VARIABLES} - all defined variables are used somewhere</li>
 *   <li>{@link #VARIABLE_TYPES_MATCH} - variable types match usage location types</li>
 *   <li>{@link #DEFER_DIRECTIVE_ON_ROOT_LEVEL} - defer not on mutation/subscription root</li>
 *   <li>{@link #DEFER_DIRECTIVE_ON_VALID_OPERATION} - defer not in subscriptions</li>
 * </ul>
 *
 * <p>See {@link OperationValidator} class documentation for a detailed traversal example.
 *
 * @see OperationValidator
 */
@PublicApi
@NullMarked
public enum OperationValidationRule {

    /** Only executable definitions (operations and fragments) are allowed. */
    EXECUTABLE_DEFINITIONS,

    /** Argument values must be compatible with their declared types. */
    ARGUMENTS_OF_CORRECT_TYPE,

    /** Fields must exist on the parent type. */
    FIELDS_ON_CORRECT_TYPE,

    /** Fragment type conditions must be on composite types (object, interface, union). */
    FRAGMENTS_ON_COMPOSITE_TYPE,

    /** Arguments must be defined on the field or directive. */
    KNOWN_ARGUMENT_NAMES,

    /** Directives must be defined in the schema and used in valid locations. */
    KNOWN_DIRECTIVES,

    /** Fragment spreads must reference defined fragments. */
    KNOWN_FRAGMENT_NAMES,

    /** Type references must exist in the schema. */
    KNOWN_TYPE_NAMES,

    /** Fragments must not form cycles through spreads. */
    NO_FRAGMENT_CYCLES,

    /** All defined fragments must be used by at least one operation. */
    NO_UNUSED_FRAGMENTS,

    /** Fields with the same response key must be mergeable. */
    OVERLAPPING_FIELDS_CAN_BE_MERGED,

    /** Fragment type conditions must overlap with the parent type. */
    POSSIBLE_FRAGMENT_SPREADS,

    /** Required (non-null without default) arguments must be provided. */
    PROVIDED_NON_NULL_ARGUMENTS,

    /** Scalar fields must not have subselections; composite fields must have them. */
    SCALAR_LEAVES,

    /** Variable default values must match the variable type. */
    VARIABLE_DEFAULT_VALUES_OF_CORRECT_TYPE,

    /** Variables must be declared with input types (scalars, enums, input objects). */
    VARIABLES_ARE_INPUT_TYPES,

    /** Anonymous operations must be the only operation in the document. */
    LONE_ANONYMOUS_OPERATION,

    /** Operation names must be unique within the document. */
    UNIQUE_OPERATION_NAMES,

    /** Fragment names must be unique within the document. */
    UNIQUE_FRAGMENT_NAMES,

    /** Non-repeatable directives must appear at most once per location. */
    UNIQUE_DIRECTIVE_NAMES_PER_LOCATION,

    /** Argument names must be unique within a field or directive. */
    UNIQUE_ARGUMENT_NAMES,

    /** Variable names must be unique within an operation. */
    UNIQUE_VARIABLE_NAMES,

    /** Subscriptions must have exactly one root field (not introspection). */
    SUBSCRIPTION_UNIQUE_ROOT_FIELD,

    /** Input object field names must be unique. */
    UNIQUE_OBJECT_FIELD_NAME,

    /** Defer directive labels must be unique static strings. */
    DEFER_DIRECTIVE_LABEL,

    /** The schema must support the operation type (query/mutation/subscription). */
    KNOWN_OPERATION_TYPES,

    /** All variable references must be defined in the operation. Requires fragment traversal. */
    NO_UNDEFINED_VARIABLES,

    /** All defined variables must be used somewhere in the operation. Requires fragment traversal. */
    NO_UNUSED_VARIABLES,

    /** Variable types must be compatible with usage location types. Requires fragment traversal. */
    VARIABLE_TYPES_MATCH,

    /** Defer directive must not be on mutation or subscription root level. Requires operation context. */
    DEFER_DIRECTIVE_ON_ROOT_LEVEL,

    /** Defer directive must not be used in subscription operations. Requires operation context. */
    DEFER_DIRECTIVE_ON_VALID_OPERATION,
}