text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.ValidationContext = undefined;
  exports.validate = validate;
  
  var _invariant = require('../jsutils/invariant');
  
  var _invariant2 = _interopRequireDefault(_invariant);
  
  var _error = require('../error');
  
  var _visitor = require('../language/visitor');
  
  var _kinds = require('../language/kinds');
  
  var _schema = require('../type/schema');
  
  var _validate = require('../type/validate');
  
  var _TypeInfo = require('../utilities/TypeInfo');
  
  var _specifiedRules = require('./specifiedRules');
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
                                                                                                                                                             * Copyright (c) 2015-present, Facebook, Inc.
                                                                                                                                                             *
                                                                                                                                                             * This source code is licensed under the MIT license found in the
                                                                                                                                                             * LICENSE file in the root directory of this source tree.
                                                                                                                                                             *
                                                                                                                                                             *  strict
                                                                                                                                                             */
  
  /**
   * Implements the "Validation" section of the spec.
   *
   * Validation runs synchronously, returning an array of encountered errors, or
   * an empty array if no errors were encountered and the document is valid.
   *
   * A list of specific validation rules may be provided. If not provided, the
   * default list of rules defined by the GraphQL specification will be used.
   *
   * Each validation rules is a function which returns a visitor
   * (see the language/visitor API). Visitor methods are expected to return
   * GraphQLErrors, or Arrays of GraphQLErrors when invalid.
   *
   * Optionally a custom TypeInfo instance may be provided. If not provided, one
   * will be created from the provided schema.
   */
  function validate(schema, ast, rules, typeInfo) {
    !ast ? (0, _invariant2.default)(0, 'Must provide document') : void 0;
    // If the schema used for validation is invalid, throw an error.
    (0, _validate.assertValidSchema)(schema);
    return visitUsingRules(schema, typeInfo || new _TypeInfo.TypeInfo(schema), ast, rules || _specifiedRules.specifiedRules);
  }
  
  /**
   * This uses a specialized visitor which runs multiple visitors in parallel,
   * while maintaining the visitor skip and break API.
   *
   * @internal
   */
  function visitUsingRules(schema, typeInfo, documentAST, rules) {
    var context = new ValidationContext(schema, documentAST, typeInfo);
    var visitors = rules.map(function (rule) {
      return rule(context);
    });
    // Visit the whole document with each instance of all provided rules.
    (0, _visitor.visit)(documentAST, (0, _visitor.visitWithTypeInfo)(typeInfo, (0, _visitor.visitInParallel)(visitors)));
    return context.getErrors();
  }
  
  /**
   * An instance of this class is passed as the "this" context to all validators,
   * allowing access to commonly useful contextual information from within a
   * validation rule.
   */
  var ValidationContext = exports.ValidationContext = function () {
    function ValidationContext(schema, ast, typeInfo) {
      _classCallCheck(this, ValidationContext);
  
      this._schema = schema;
      this._ast = ast;
      this._typeInfo = typeInfo;
      this._errors = [];
      this._fragmentSpreads = new Map();
      this._recursivelyReferencedFragments = new Map();
      this._variableUsages = new Map();
      this._recursiveVariableUsages = new Map();
    }
  
    ValidationContext.prototype.reportError = function reportError(error) {
      this._errors.push(error);
    };
  
    ValidationContext.prototype.getErrors = function getErrors() {
      return this._errors;
    };
  
    ValidationContext.prototype.getSchema = function getSchema() {
      return this._schema;
    };
  
    ValidationContext.prototype.getDocument = function getDocument() {
      return this._ast;
    };
  
    ValidationContext.prototype.getFragment = function getFragment(name) {
      var fragments = this._fragments;
      if (!fragments) {
        this._fragments = fragments = this.getDocument().definitions.reduce(function (frags, statement) {
          if (statement.kind === _kinds.Kind.FRAGMENT_DEFINITION) {
            frags[statement.name.value] = statement;
          }
          return frags;
        }, Object.create(null));
      }
      return fragments[name];
    };
  
    ValidationContext.prototype.getFragmentSpreads = function getFragmentSpreads(node) {
      var spreads = this._fragmentSpreads.get(node);
      if (!spreads) {
        spreads = [];
        var setsToVisit = [node];
        while (setsToVisit.length !== 0) {
          var set = setsToVisit.pop();
          for (var i = 0; i < set.selections.length; i++) {
            var selection = set.selections[i];
            if (selection.kind === _kinds.Kind.FRAGMENT_SPREAD) {
              spreads.push(selection);
            } else if (selection.selectionSet) {
              setsToVisit.push(selection.selectionSet);
            }
          }
        }
        this._fragmentSpreads.set(node, spreads);
      }
      return spreads;
    };
  
    ValidationContext.prototype.getRecursivelyReferencedFragments = function getRecursivelyReferencedFragments(operation) {
      var fragments = this._recursivelyReferencedFragments.get(operation);
      if (!fragments) {
        fragments = [];
        var collectedNames = Object.create(null);
        var nodesToVisit = [operation.selectionSet];
        while (nodesToVisit.length !== 0) {
          var _node = nodesToVisit.pop();
          var spreads = this.getFragmentSpreads(_node);
          for (var i = 0; i < spreads.length; i++) {
            var fragName = spreads[i].name.value;
            if (collectedNames[fragName] !== true) {
              collectedNames[fragName] = true;
              var fragment = this.getFragment(fragName);
              if (fragment) {
                fragments.push(fragment);
                nodesToVisit.push(fragment.selectionSet);
              }
            }
          }
        }
        this._recursivelyReferencedFragments.set(operation, fragments);
      }
      return fragments;
    };
  
    ValidationContext.prototype.getVariableUsages = function getVariableUsages(node) {
      var usages = this._variableUsages.get(node);
      if (!usages) {
        var newUsages = [];
        var typeInfo = new _TypeInfo.TypeInfo(this._schema);
        (0, _visitor.visit)(node, (0, _visitor.visitWithTypeInfo)(typeInfo, {
          VariableDefinition: function VariableDefinition() {
            return false;
          },
          Variable: function Variable(variable) {
            newUsages.push({ node: variable, type: typeInfo.getInputType() });
          }
        }));
        usages = newUsages;
        this._variableUsages.set(node, usages);
      }
      return usages;
    };
  
    ValidationContext.prototype.getRecursiveVariableUsages = function getRecursiveVariableUsages(operation) {
      var usages = this._recursiveVariableUsages.get(operation);
      if (!usages) {
        usages = this.getVariableUsages(operation);
        var fragments = this.getRecursivelyReferencedFragments(operation);
        for (var i = 0; i < fragments.length; i++) {
          Array.prototype.push.apply(usages, this.getVariableUsages(fragments[i]));
        }
        this._recursiveVariableUsages.set(operation, usages);
      }
      return usages;
    };
  
    ValidationContext.prototype.getType = function getType() {
      return this._typeInfo.getType();
    };
  
    ValidationContext.prototype.getParentType = function getParentType() {
      return this._typeInfo.getParentType();
    };
  
    ValidationContext.prototype.getInputType = function getInputType() {
      return this._typeInfo.getInputType();
    };
  
    ValidationContext.prototype.getParentInputType = function getParentInputType() {
      return this._typeInfo.getParentInputType();
    };
  
    ValidationContext.prototype.getFieldDef = function getFieldDef() {
      return this._typeInfo.getFieldDef();
    };
  
    ValidationContext.prototype.getDirective = function getDirective() {
      return this._typeInfo.getDirective();
    };
  
    ValidationContext.prototype.getArgument = function getArgument() {
      return this._typeInfo.getArgument();
    };
  
    return ValidationContext;
  }();