all files / lib/ Resolution.js

100% Statements 50/50
100% Branches 14/14
100% Functions 14/14
100% Lines 50/50
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                287× 287×   287×                   238×     237×     237×             204×             66×             1201×                                     402×   402× 150×     144×         393×             67×             644×             269× 269× 269×               269× 137× 14×   123×     132× 132× 132× 52× 52×   80×                              
"use strict";
/*jshint eqnull:true */
var EventEmitter = require('events').EventEmitter;
var util = require('./util');
var ResolutionError = require('./ResolutionError');
 
var assert = util.assert;
 
/**
 * <strong>Private constructor</strong>. Instances are normally created internally and passed to resolvers.
 * @constructor
 */
function Resolution() {
  EventEmitter.call(this);
  this._done = false;
 
  this.fail = this.fail.bind(this); // Bind so resolution.fail can be used as a promise catch() handler
}
util.inherits(Resolution, EventEmitter);
 
/** @lends Resolution# */
var R = Resolution.prototype;
 
/**
 * Resolve the given instance of a component. This will be come the result of the {@link Container#resolve} call that
 * triggered this resolution.
 * @param {*|null} instance The instance to resolve.
 */
R.resolve = function(instance) {
  assert(instance !== undefined,
    "Resolver attempted to resolve undefined instance",
    ResolutionError);
  assert(!this._committed,
    "Resolution has already been committed",
    ResolutionError);
  this._instance = instance;
};
 
/**
 * Determine if an instance has been resolved.
 * @returns {boolean}
 */
R.resolved = function() {
  return this._instance !== undefined;
};
 
/**
 * Fail this resolution with the given error.
 * @param {Error} error The error representing the cause of the resolution failure.
 */
R.fail = function(error) {
  this._error = error;
};
 
/**
 * Determine if the resolution has failed.
 * @returns {boolean} <code>true</code> if #fail was called with an error.
 */
R.failed = function() {
  return !!this._error;
};
 
/**
 * Mark this resolution as done regardless of the current resolved or failed state. "Done" means that, even though
 * a resolver may call the <code>next()</code> callback, the process will be aborted and no further resolvers will
 * be invoked.
 */
R.done = function() {
  this._done = true;
};
 
/**
 * Get the instance that will be the result of the component resolution. This instance is set by
 * the {@link #resolve} method.
 * @param {boolean|undefined} require <code>true</code> if the instance must be defined, <code>false</code> if the
 *        instance must not be defined, or omit the parameter if no defined checks should occur.
 * @returns {*|null}
 * @throws ResolutionError when <code>require</code> is <code>true</code> and the instance isn't defined
 *                         or <code>require</code> is <code>false</code> and the instance is defined.
 */
R.instance = function(require) {
  var i = this._instance;
 
  if (require !== undefined) {
    assert(!require || i != null,
      "Resolver requires instance to be resolved",
      ResolutionError);
    assert(require || i == null,
      "Resolver requires instance to not yet be resolved",
      ResolutionError);
  }
 
  return i;
};
 
/**
 * Get the error that failed the resolution. This error was set by the {@link #fail} method.
 * @returns {Error|null} The resolution failure error, or <code>null</code> if not failed.
 */
R.error = function() {
  return this._error || null;
};
 
/**
 * Determine if this resolution is done; that further resolvers will not be invoked.
 * @returns {boolean} The done state of this component resolution.
 */
R.isDone = function() {
  return !!this._done;
};
 
/**
 * Mark this bastard as committed.
 * @private
 */
R._commit = function() {
  assert(!this._committed, "Resolution#commit called twice");
  this._committed = true;
  this.emit('committed', this);
};
 
/**
 * Obtain a Promise that will be resolved when the final instance and state has been resolved.
 * Otherwise, it will be rejected with the cause of the resolution failure.
 * @returns {Promise}
 */
R.committed = function() {
  if (this._committed) {
    if (this.failed()) {
      return Promise.reject(this.error());
    }
    return Promise.resolve(this.instance());
  }
 
  return new Promise(function(resolve, reject) {
    this.once('committed', function() {
      if (this.failed()) {
        reject(this.error());
        return;
      }
      resolve(this.instance());
    }.bind(this));
  }.bind(this));
};
 
/**
 * Obtain a string representation of this instance.
 * @returns {string}
 */
R.toString = function() {
  return "Resolution {" +
    "instance: " + this.instance() +
    ", error: " + this.error() +
    ", done: " + this.isDone() +
    "}";
};
 
module.exports = Resolution;