all files / lib/ ResolutionContext.js

100% Statements 47/47
100% Branches 17/17
100% Functions 14/14
100% Lines 47/47
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163                298×               294× 1458×                   441×                               449×               255×                                       13× 11×                     139×                               158× 158× 11×     158×         158× 158×   142×     142× 142× 105× 105×       158× 121×   113×                          
"use strict";
 
var Dependency = require('./Dependency');
 
/**
 * <strong>Private constructor</strong>. Instances are normally created internally and passed to resolvers.
 * @param options
 * @constructor
 */
function ResolutionContext(options) {
  if (!options ||
    !options.container ||
    !options.key ||
    options.component === undefined ||
    !options.store)
  {
    throw new Error("Must supply options: container, key, component, store");
  }
 
  Object.keys(options).forEach(function(key) {
    this['_' + key] = options[key];
  }.bind(this));
}
 
/** @lends ResolutionContext# */
var RC = ResolutionContext.prototype;
 
/**
 * Obtain the previous context in the resolution chain.
 * @returns {ResolutionContext|null}
 */
RC.previous = function() {
  return this._previous || null;
};
 
/**
 * Obtain a list of keys for resolutions that triggered this resolution. This list will
 * always have at least one element, and the last element always being the same as
 * this context's #key result.
 * @returns {Array.<String>} A stack of key names.
 */
RC.keyStack = function() {
  var stack = [];
  var ctx = this;
  do {
    stack.unshift(ctx.key());
    ctx = ctx.previous();
  } while (ctx);
  return stack;
};
 
/**
 * Get the key of the component being resolved.
 * @returns {String} The component key.
 */
RC.key = function() {
  return this._key;
};
 
/**
 * Get the component being resolved. This is the same instance
 * that was passed into the {@link Container#register} method.
 * @returns {*}
 */
RC.component = function() {
  return this._component;
};
 
/**
 * Provides access to arbitrary data that is stored at the scope of the component registration.
 * This allows a resolver to preserve state across several resolutions of a single component.
 *
 * @param key {String} The optional data key.
 * @param value {*} The optional data value.
 *
 * @example
 * // Set a value
 * ctx.store('dogCount', 3);
 *
 * // Get a value
 * ctx.store('dogCount'); // -> 3
 *
 * // Get all values
 * ctx.store(); // -> { 'dogCount': 3 }
 */
RC.store = function(key, value) {
  if (key === undefined) {
    return this._store;
  } else if (value === undefined) {
    return this._store[key];
  } else {
    this._store[key] = value;
  }
};
 
/**
 *
 * @param dep
 * @returns {*}
 * @private
 */
RC._resolveDep = function(dep) {
  return this._container.resolve(dep.key(), {
    optional: dep.optional(),
    resolutionContext: this
  });
};
 
/**
 * Resolve the given Dependency instance or instances using the same container in which
 * the component for this resolution lives.
 *
 * @param {String|Array.<String>|Dependency|Array.<Dependency>} deps A Dependency instance or Array of instances.
 * @param {Object} [options] Configuration options.
 * @param {boolean} [options.optional=false] When <code>true</code>, the specified dependencies are treated as optional.
 *
 * @returns {Promise} A promise that resolves a structure containing resolved dependencies: <code>{map: {}, list: Array}</code>.
 */
RC.resolve = function(deps, options) {
  var single = !Array.isArray(deps);
  if (single) {
    deps = [ deps ];
  }
 
  var struct = {
    map: {},
    list: []
  };
 
  var nextIndex = 0;
  var promises =
    deps.map(function(dep) {
      return Dependency.getOrCreate(dep, options);
    })
    .map(function(dep) {
      var index = nextIndex++;
      return this._resolveDep(dep).then(function(resolvedDep) {
        struct.map[dep.key()] = resolvedDep;
        struct.list[index] = resolvedDep;
      });
    }.bind(this), {});
 
  return Promise.all(promises).then(function() {
    if (single) {
      return struct.list[0];
    }
    return struct;
  });
};
 
/**
 * Obtain a string representation of this instance.
 * @returns {string}
 */
RC.toString = function() {
  return "ResolutionContext {" +
    "keyStack: " + JSON.stringify(this.keyStack()) +
    ", storeKeys: " + JSON.stringify(Object.keys(this.store())) +
    "}";
};
 
module.exports = ResolutionContext;