Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

pfchangs / react-relay   js

Repository URL to install this package:

Version: 0.7.1-ccinternal 

/ lib / RelayFragmentReference.js

/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule RelayFragmentReference
 * @typechecks
 * 
 */

'use strict';

var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];

var _extends = require('babel-runtime/helpers/extends')['default'];

var QueryBuilder = require('./QueryBuilder');

var forEachObject = require('fbjs/lib/forEachObject');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');

/**
 * @internal
 *
 * RelayFragmentReference is the return type of fragment composition:
 *
 *   fragment on Foo {
 *     ${Child.getFragment('bar', {baz: variables.qux})}
 *   }
 *
 * Whereas a fragment defines a sub-query's structure, a fragment reference is
 * a particular instantiation of the fragment as it is composed within a query
 * or another fragment. It encodes the source fragment, initial variables, and
 * a mapping from variables in the composing query's (or fragment's) scope to
 * variables in the fragment's scope.
 *
 * The variable mapping is represented by `variableMapping`, a dictionary that
 * maps from names of variables in the parent scope to variables that exist in
 * the fragment. Example:
 *
 * ```
 * // Fragment:
 * var Container = Relay.createContainer(..., {
 *   initialVariables: {
 *     private: 'foo',
 *     public: 'bar',
 *     variable: null,
 *   },
 *   fragments: {
 *     foo: ...
 *   }
 * });
 *
 * // Reference:
 * ${Container.getQuery(
 *   'foo',
 *   // Variable Mapping:
 *   {
 *     public: 'BAR',
 *     variable: variables.source,
 *   }
 * )}
 * ```
 *
 * When evaluating the referenced fragment, `$public` will be overridden with
 * `'Bar'`. The value of `$variable` will become the value of `$source` in the
 * outer scope. This is analagous to:
 *
 * ```
 * function inner(private = 'foo', public = 'bar', variable) {}
 * function outer(source) {
 *   inner(public = 'BAR', variable = source);
 * }
 * ```
 *
 * Where the value of the inner `variable` depends on how `outer` is called.
 *
 * The `prepareVariables` function allows for variables to be modified based on
 * the runtime environment or route name.
 */

var RelayFragmentReference = (function () {
  RelayFragmentReference.createForContainer = function createForContainer(fragmentGetter, initialVariables, variableMapping, prepareVariables) {
    var reference = new RelayFragmentReference(fragmentGetter, initialVariables, variableMapping, prepareVariables);
    reference._isContainerFragment = true;
    return reference;
  };

  function RelayFragmentReference(fragmentGetter, initialVariables, variableMapping, prepareVariables) {
    _classCallCheck(this, RelayFragmentReference);

    this._initialVariables = initialVariables || {};
    this._fragment = undefined;
    this._fragmentGetter = fragmentGetter;
    this._isContainerFragment = false;
    this._isDeferred = false;
    this._variableMapping = variableMapping;
    this._prepareVariables = prepareVariables;
  }

  /**
   * Mark this usage of the fragment as deferred.
   */

  RelayFragmentReference.prototype.defer = function defer() {
    this._isDeferred = true;
    return this;
  };

  /**
   * Mark this fragment for inclusion only if the given variable is truthy.
   */

  RelayFragmentReference.prototype['if'] = function _if(value) {
    var callVariable = QueryBuilder.getCallVariable(value);
    !callVariable ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayFragmentReference: Invalid value `%s` supplied to `if()`. ' + 'Expected a variable.', callVariable) : invariant(false) : undefined;
    this._addCondition(function (variables) {
      return !!variables[callVariable.callVariableName];
    });
    return this;
  };

  /**
   * Mark this fragment for inclusion only if the given variable is falsy.
   */

  RelayFragmentReference.prototype.unless = function unless(value) {
    var callVariable = QueryBuilder.getCallVariable(value);
    !callVariable ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayFragmentReference: Invalid value `%s` supplied to `unless()`. ' + 'Expected a variable.', callVariable) : invariant(false) : undefined;
    this._addCondition(function (variables) {
      return !variables[callVariable.callVariableName];
    });
    return this;
  };

  /**
   * @private
   */

  RelayFragmentReference.prototype._getFragment = function _getFragment() {
    var fragment = this._fragment;
    if (fragment == null) {
      fragment = this._fragmentGetter();
      this._fragment = fragment;
    }
    return fragment;
  };

  /**
   * Get the referenced fragment if all conditions are met.
   */

  RelayFragmentReference.prototype.getFragment = function getFragment(variables) {
    // determine if the variables match the supplied if/unless conditions
    var conditions = this._conditions;
    if (conditions && !conditions.every(function (cb) {
      return cb(variables);
    })) {
      return null;
    }
    return this._getFragment();
  };

  /**
   * Get the variables to pass to the referenced fragment, accounting for
   * initial values, overrides, and route-specific variables.
   */

  RelayFragmentReference.prototype.getVariables = function getVariables(route, variables) {
    var _this = this;

    var innerVariables = _extends({}, this._initialVariables);

    // map variables from outer -> inner scope
    var variableMapping = this._variableMapping;
    if (variableMapping) {
      forEachObject(variableMapping, function (value, name) {
        var callVariable = QueryBuilder.getCallVariable(value);
        if (callVariable) {
          value = variables[callVariable.callVariableName];
        }
        if (value === undefined) {
          process.env.NODE_ENV !== 'production' ? warning(false, 'RelayFragmentReference: Variable `%s` is undefined in fragment ' + '`%s`.', name, _this._getFragment().name) : undefined;
        } else {
          innerVariables[name] = value;
        }
      });
    }

    var prepareVariables = this._prepareVariables;
    if (prepareVariables) {
      innerVariables = prepareVariables(innerVariables, route);
    }

    return innerVariables;
  };

  RelayFragmentReference.prototype.isContainerFragment = function isContainerFragment() {
    return this._isContainerFragment;
  };

  RelayFragmentReference.prototype.isDeferred = function isDeferred() {
    return this._isDeferred;
  };

  RelayFragmentReference.prototype._addCondition = function _addCondition(condition) {
    var conditions = this._conditions;
    if (!conditions) {
      conditions = [];
      this._conditions = conditions;
    }
    conditions.push(condition);
  };

  return RelayFragmentReference;
})();

module.exports = RelayFragmentReference;