<commit_before>'use strict';

var debug = require('debug')('base:templates:render');
var utils = require('../utils');

module.exports = function(proto) {
  debug('loading render methods onto %s, <%s>', proto.constructor.name);

  /**
   * Set view types for a collection.
   *
   * @param {String} `plural` e.g. `pages`
   * @param {Object} `options`
   */

  if (typeof proto.viewType !== 'function') {
    proto.viewType = viewType;
  }

  function viewType(plural, types) {
    var len = types.length, i = 0;
    while (len--) {
      var type = types[i++];
      this.viewTypes[type] = this.viewTypes[type] || [];
      if (this.viewTypes[type].indexOf(plural) === -1) {
        this.viewTypes[type].push(plural);
      }
    }
    return types;
  }

  /**
   * Iterates over `renderable` view collections
   * and returns the first view that matches the
   * given `view` name
   */

  function findView(app, name) {
    var keys = app.viewTypes.renderable;
    var len = keys.length;
    var i = -1;

    var res = null;
    while (++i < len) {
      res = app.find(name, keys[i]);
      if (res) {
        break;
      }
    }
    return res;
  }

  /**
   * Get a view from the specified collection, or list,
   * or iterate over view collections until the view
   * is found.
   */

  function getView(app, view) {
    if (typeof view !== 'string') {
      return view;
    }
    if (app.isCollection) {
      view = app.getView(view);

    } else if (app.isList) {
      view = app.getItem(view);

    } else {
      view = findView(app, view);
    }
    return view;
  }

  /**
   * Compile `content` with the given `locals`.
   *
   * ```js
   * var indexPage = app.page('some-index-page.hbs');
   * var view = app.compile(indexPage);
   * // view.fn => [function]
   *
   * // you can call the compiled function more than once
   * // to render the view with different data
   * view.fn({title: 'Foo'});
   * view.fn({title: 'Bar'});
   * view.fn({title: 'Baz'});
   * ```
   *
   * @name .compile
   * @param  {Object|String} `view` View object.
   * @param  {Object} `locals`
   * @param  {Boolean} `isAsync` Load async helpers
   * @return {Object} View object with compiled `view.fn` property.
   * @api public
   */

  proto.compile = function(view, locals, isAsync) {
    if (typeof locals === 'boolean') {
      isAsync = locals;
      locals = {};
    }

    if (typeof locals === 'function' || typeof isAsync === 'function') {
      throw this.formatError('compile', 'callback');
    }

    locals = utils.extend({settings: {}}, locals);

    // if `view` is a string, see if it's a cached view
    if (typeof view === 'string') {
      view = getView(this, view);
    }

    // handle `preCompile` middleware
    this.handleOnce('preCompile', view);

    // determine the name of the engine to use
    var ext = utils.resolveEngineExt(view, locals, this.options);
    // get the actual engine (object)
    var engine = this.getEngine(ext);

    // throw if an engine is not defined
    if (typeof engine === 'undefined') {
      throw this.formatError('compile', 'engine', formatExtError(view, ext));
    }

    // clean up engine name, for consistency
    ext = engine.options.ext;
    engine.options.engineName = engine.options.name;
    delete engine.options.name;

    // get engine options (settings)
    var engineOpts = utils.merge({}, locals.settings, engine.options);
    console.log(view.context)
    var ctx = cacheContext(this, view, locals);

    // apply layout
    view = this.applyLayout(view);

    // Bind context to helpers before passing to the engine.
    this.bindHelpers(view, ctx, (ctx.async = !!isAsync));

    // shallow clone the context and locals
    engineOpts = utils.merge({}, ctx, engineOpts, this.mergePartials(engineOpts));

    // compile the string
    view.fn = engine.compile(view.content, engineOpts);

    // handle `postCompile` middleware
    this.handleOnce('postCompile', view);
    return view;
  };

  /**
   * Asynchronously compile `content` with the given `locals` and callback. _(fwiw, this
   * method name uses the unconventional "*Async" nomenclature to allow us to preserve the
   * synchronous behavior of the `view.compile` method as well as the name)_.
   *
   * ```js
   * var indexPage = app.page('some-index-page.hbs');
   * app.compileAsync(indexPage, function(err, view) {
   *   // view.fn => compiled function
   * });
   * ```
   * @name .compileAsync
   * @param  {Object|String} `view` View object.
   * @param  {Object} `locals`
   * @param  {Boolean} `isAsync` Pass true to load helpers as async (mostly used internally)
   * @param {Function} `callback` function that exposes `err` and the `view` object with compiled `view.fn` property
   * @api public
   */

  proto.compileAsync = function(view, locals, isAsync, cb) {
    if (typeof locals === 'function') {
      return this.compileAsync(view, {}, false, locals);
    }
    if (typeof isAsync === 'function') {
      return this.compileAsync(view, locals, false, isAsync);
    }
    if (typeof locals === 'boolean') {
      return this.compileAsync(view, {}, locals, isAsync);
    }

    // if `view` is a string, see if it's a cached view
    if (typeof view === 'string') {
      view = getView(this, view);
    }

    locals = utils.extend({settings: {}}, locals);
    var ctx = this.context(view, locals);
    var app = this;

    // handle `preCompile` middleware
    this.handleOnce('preCompile', view, function(err, file) {
      if (err) return cb(err);

      // determine the name of the engine to use
      var ext = utils.resolveEngineExt(file, ctx, app.options);

      // get the actual engine (object)
      var engine = app.getEngine(ext);

      if (typeof engine === 'undefined') {
        cb(app.formatError('compile', 'engine', formatExtError(file, ext)));
        return;
      }

      ext = engine.options.ext;
      engine.options.engineName = engine.options.name;
      delete engine.options.name;

      // get engine options (settings)
      var engineOpts = utils.merge({}, locals.settings, engine.options);

      // apply layout
      app.applyLayoutAsync(file, function(err, view) {
        if (err) return cb(err);

        // Bind context to helpers before passing to the engine.
        app.bindHelpers(view, ctx, (ctx.async = !!isAsync));

        app.mergePartialsAsync(engineOpts, function(err, partials) {
          if (err) return cb(err);

          // shallow clone the context and engineOpts
          var mergedSettings = utils.merge({}, engineOpts, ctx, partials);

          var content = view.content;
          if (view.engineStack.hasOwnProperty(ext)) {
            content = view.engineStack[ext].content;
          }

          // compile the string
          view.fn = engine.compile(content, mergedSettings);
          utils.engineStack(view, ext, view.fn, content);

          // handle `postCompile` middleware
          app.handleOnce('postCompile', view, cb);
        });
      });
    });
  };

  /**
   * Render a view with the given `locals` and `callback`.
   *
   * ```js
   * var blogPost = app.post.getView('2015-09-01-foo-bar');
   * app.render(blogPost, {title: 'Foo'}, function(err, view) {
   *   // `view` is an object with a rendered `content` property
   * });
   * ```
   * @name .render
   * @param  {Object|String} `view` Instance of `View`
   * @param  {Object} `locals` Locals to pass to template engine.
   * @param  {Function} `callback`
   * @api public
   */

  proto.render = function(view, locals, cb) {
    if (typeof locals === 'function') {
      cb = locals;
      locals = {};
    }

    if (typeof cb !== 'function') {
      throw this.formatError('render', 'callback');
    }

    // if `view` is a string, see if it's a cached view
    if (typeof view === 'string') {
      view = getView(this, view);
    }

    var ctx = cacheContext(this, view, locals);
    var app = this;

    // handle `preRender` middleware
    this.handleOnce('preRender', view, function(err, file) {
      if (err) return cb(err);

      // get the engine
      var ext = utils.resolveEngineExt(file, ctx, app.options);
      var engine = app.getEngine(ext);

      if (!engine) {
        cb(app.formatError('render', 'engine', formatExtError(file, ext)));
        return;
      }

      // since we already merged context, add it to a property
      // so it can be used by `compile`
      if (app.options.cacheContext === true) {
        file._context = ctx;
      }

      // compile the view
      app.compileAsync(file, ctx, true, function(err, view) {
        if (err) return cb(err);

        // build the context one more time in case it has changed
        var context = cacheContext(app, file, ctx);

        // render the view
        engine.render(view.fn, context, function(err, res) {
          if (err) {
            // rethrow is a noop if `options.rethrow` is not true
            var renderErr = app.rethrow('render', err, view, context);
            if (app.hasListeners('error')) {
              app.emit('error', renderErr || err);
            }
            cb(renderErr || err);
            return;
          }

          view.localsStack.push(locals);
          view.content = res;
          delete view._context;

          // handle `postRender` middleware
          app.handleOnce('postRender', view, cb);
        });
      });
    });
  };
};

function formatExtError(view, ext) {
  if (ext && typeof ext === 'string' && ext.trim()) {
    return ext;
  }
  return view.basename;
}

function cacheContext(app, file, context) {
  if (typeof app.options.cacheContext === 'function') {
    file._context = app.options.cacheContext(file, context, app);
  } else if (app.options.cacheContext === true && typeof file.context === 'function') {
    return (file._context || file.context(context));
  } else if (typeof file.context === 'function') {
    return file.context(context);
  } else {
    return context;
  }
}
<commit_msg>cleanup<commit_after>'use strict';

var debug = require('debug')('base:templates:render');
var utils = require('../utils');

module.exports = function(proto) {
  debug('loading render methods onto %s, <%s>', proto.constructor.name);

  /**
   * Set view types for a collection.
   *
   * @param {String} `plural` e.g. `pages`
   * @param {Object} `options`
   */

  if (typeof proto.viewType !== 'function') {
    proto.viewType = viewType;
  }

  function viewType(plural, types) {
    var len = types.length, i = 0;
    while (len--) {
      var type = types[i++];
      this.viewTypes[type] = this.viewTypes[type] || [];
      if (this.viewTypes[type].indexOf(plural) === -1) {
        this.viewTypes[type].push(plural);
      }
    }
    return types;
  }

  /**
   * Iterates over `renderable` view collections
   * and returns the first view that matches the
   * given `view` name
   */

  function findView(app, name) {
    var keys = app.viewTypes.renderable;
    var len = keys.length;
    var i = -1;

    var res = null;
    while (++i < len) {
      res = app.find(name, keys[i]);
      if (res) {
        break;
      }
    }
    return res;
  }

  /**
   * Get a view from the specified collection, or list,
   * or iterate over view collections until the view
   * is found.
   */

  function getView(app, view) {
    if (typeof view !== 'string') {
      return view;
    }
    if (app.isCollection) {
      view = app.getView(view);

    } else if (app.isList) {
      view = app.getItem(view);

    } else {
      view = findView(app, view);
    }
    return view;
  }

  /**
   * Compile `content` with the given `locals`.
   *
   * ```js
   * var indexPage = app.page('some-index-page.hbs');
   * var view = app.compile(indexPage);
   * // view.fn => [function]
   *
   * // you can call the compiled function more than once
   * // to render the view with different data
   * view.fn({title: 'Foo'});
   * view.fn({title: 'Bar'});
   * view.fn({title: 'Baz'});
   * ```
   *
   * @name .compile
   * @param  {Object|String} `view` View object.
   * @param  {Object} `locals`
   * @param  {Boolean} `isAsync` Load async helpers
   * @return {Object} View object with compiled `view.fn` property.
   * @api public
   */

  proto.compile = function(view, locals, isAsync) {
    if (typeof locals === 'boolean') {
      isAsync = locals;
      locals = {};
    }

    if (typeof locals === 'function' || typeof isAsync === 'function') {
      throw this.formatError('compile', 'callback');
    }

    locals = utils.extend({settings: {}}, locals);

    // if `view` is a string, see if it's a cached view
    if (typeof view === 'string') {
      view = getView(this, view);
    }

    // handle `preCompile` middleware
    this.handleOnce('preCompile', view);

    // determine the name of the engine to use
    var ext = utils.resolveEngineExt(view, locals, this.options);
    // get the actual engine (object)
    var engine = this.getEngine(ext);

    // throw if an engine is not defined
    if (typeof engine === 'undefined') {
      throw this.formatError('compile', 'engine', formatExtError(view, ext));
    }

    // clean up engine name, for consistency
    ext = engine.options.ext;
    engine.options.engineName = engine.options.name;
    delete engine.options.name;

    // get engine options (settings)
    var engineOpts = utils.merge({}, locals.settings, engine.options);
    var ctx = cacheContext(this, view, locals);

    // apply layout
    view = this.applyLayout(view);

    // Bind context to helpers before passing to the engine.
    this.bindHelpers(view, ctx, (ctx.async = !!isAsync));

    // shallow clone the context and locals
    engineOpts = utils.merge({}, ctx, engineOpts, this.mergePartials(engineOpts));

    // compile the string
    view.fn = engine.compile(view.content, engineOpts);

    // handle `postCompile` middleware
    this.handleOnce('postCompile', view);
    return view;
  };

  /**
   * Asynchronously compile `content` with the given `locals` and callback. _(fwiw, this
   * method name uses the unconventional "*Async" nomenclature to allow us to preserve the
   * synchronous behavior of the `view.compile` method as well as the name)_.
   *
   * ```js
   * var indexPage = app.page('some-index-page.hbs');
   * app.compileAsync(indexPage, function(err, view) {
   *   // view.fn => compiled function
   * });
   * ```
   * @name .compileAsync
   * @param  {Object|String} `view` View object.
   * @param  {Object} `locals`
   * @param  {Boolean} `isAsync` Pass true to load helpers as async (mostly used internally)
   * @param {Function} `callback` function that exposes `err` and the `view` object with compiled `view.fn` property
   * @api public
   */

  proto.compileAsync = function(view, locals, isAsync, cb) {
    if (typeof locals === 'function') {
      return this.compileAsync(view, {}, false, locals);
    }
    if (typeof isAsync === 'function') {
      return this.compileAsync(view, locals, false, isAsync);
    }
    if (typeof locals === 'boolean') {
      return this.compileAsync(view, {}, locals, isAsync);
    }

    // if `view` is a string, see if it's a cached view
    if (typeof view === 'string') {
      view = getView(this, view);
    }

    locals = utils.extend({settings: {}}, locals);
    var ctx = this.context(view, locals);
    var app = this;

    // handle `preCompile` middleware
    this.handleOnce('preCompile', view, function(err, file) {
      if (err) return cb(err);

      // determine the name of the engine to use
      var ext = utils.resolveEngineExt(file, ctx, app.options);

      // get the actual engine (object)
      var engine = app.getEngine(ext);

      if (typeof engine === 'undefined') {
        cb(app.formatError('compile', 'engine', formatExtError(file, ext)));
        return;
      }

      ext = engine.options.ext;
      engine.options.engineName = engine.options.name;
      delete engine.options.name;

      // get engine options (settings)
      var engineOpts = utils.merge({}, locals.settings, engine.options);

      // apply layout
      app.applyLayoutAsync(file, function(err, view) {
        if (err) return cb(err);

        // Bind context to helpers before passing to the engine.
        app.bindHelpers(view, ctx, (ctx.async = !!isAsync));

        app.mergePartialsAsync(engineOpts, function(err, partials) {
          if (err) return cb(err);

          // shallow clone the context and engineOpts
          var mergedSettings = utils.merge({}, engineOpts, ctx, partials);

          var content = view.content;
          if (view.engineStack.hasOwnProperty(ext)) {
            content = view.engineStack[ext].content;
          }

          // compile the string
          view.fn = engine.compile(content, mergedSettings);
          utils.engineStack(view, ext, view.fn, content);

          // handle `postCompile` middleware
          app.handleOnce('postCompile', view, cb);
        });
      });
    });
  };

  /**
   * Render a view with the given `locals` and `callback`.
   *
   * ```js
   * var blogPost = app.post.getView('2015-09-01-foo-bar');
   * app.render(blogPost, {title: 'Foo'}, function(err, view) {
   *   // `view` is an object with a rendered `content` property
   * });
   * ```
   * @name .render
   * @param  {Object|String} `view` Instance of `View`
   * @param  {Object} `locals` Locals to pass to template engine.
   * @param  {Function} `callback`
   * @api public
   */

  proto.render = function(view, locals, cb) {
    if (typeof locals === 'function') {
      cb = locals;
      locals = {};
    }

    if (typeof cb !== 'function') {
      throw this.formatError('render', 'callback');
    }

    // if `view` is a string, see if it's a cached view
    if (typeof view === 'string') {
      view = getView(this, view);
    }

    var ctx = cacheContext(this, view, locals);
    var app = this;

    // handle `preRender` middleware
    this.handleOnce('preRender', view, function(err, file) {
      if (err) return cb(err);

      // get the engine
      var ext = utils.resolveEngineExt(file, ctx, app.options);
      var engine = app.getEngine(ext);

      if (!engine) {
        cb(app.formatError('render', 'engine', formatExtError(file, ext)));
        return;
      }

      // since we already merged context, add it to a property
      // so it can be used by `compile`
      if (app.options.cacheContext === true) {
        file._context = ctx;
      }

      // compile the view
      app.compileAsync(file, ctx, true, function(err, view) {
        if (err) return cb(err);

        // build the context one more time in case it has changed
        var context = cacheContext(app, file, ctx);

        // render the view
        engine.render(view.fn, context, function(err, res) {
          if (err) {
            // rethrow is a noop if `options.rethrow` is not true
            var renderErr = app.rethrow('render', err, view, context);
            if (app.hasListeners('error')) {
              app.emit('error', renderErr || err);
            }
            cb(renderErr || err);
            return;
          }

          view.localsStack.push(locals);
          view.content = res;
          delete view._context;

          // handle `postRender` middleware
          app.handleOnce('postRender', view, cb);
        });
      });
    });
  };
};

function formatExtError(view, ext) {
  if (ext && typeof ext === 'string' && ext.trim()) {
    return ext;
  }
  return view.basename;
}

function cacheContext(app, file, context) {
  if (typeof app.options.cacheContext === 'function') {
    file._context = app.options.cacheContext(file, context, app);
  } else if (app.options.cacheContext === true && typeof file.context === 'function') {
    return (file._context || file.context(context));
  } else if (typeof file.context === 'function') {
    return file.context(context);
  } else {
    return context;
  }
}
<|endoftext|>


<commit_before>const Chalk = require('chalk')
const _ = require('lodash')
const Utils = require('../utils')

const NONE = Chalk.grey('▪')
const COLORS = ['yellow', 'green', 'magenta', 'red', 'blue', 'cyan']
const METHODS = ['GET', 'POST', 'DELETE', 'PUT', 'PATCH']
const AUTH_MAP = {
  required: Chalk.green('✔'),
  optional: Chalk.yellow('OPTIONAL'),
  try: Chalk.red('TRY'),
  '': NONE
}

function colorize (str, collection, shift = 0, alt) {
  let color = COLORS[((collection.indexOf(str) + 1) + shift) % COLORS.length]
  if (!Chalk[color]) return colorize(str, collection, shift + 1, alt)
  return Chalk[color](alt || str)
}

// let _controllers = []
// function controller_color (controller) {
//   if (_controllers.indexOf(controller) === -1) { _controllers.push(controller) }
//   return colorize(controller, _controllers, 4)
// }

function method_color (method, alt) {
  return colorize(method, METHODS, 0, alt)
}

function print_route_table (routes) {
  // Extract routes
  let _routes = routes.map((route) => {
    let controller, fn
    let id = route.settings.id || ''
    let s = id.split('.')

    controller = (s[0] && s[0].length) ? s[0] : 'Default'
    s.shift()
    fn = s.length ? s.join('_') : NONE

    // Auth
    let auth = NONE
    let scope = NONE
    if (route.settings.auth) {
      auth = route.settings.auth.mode
      // Scope
      if (route.settings.auth.access) {
        scope = route.settings.auth.access.map(acl => String(acl.scope.selection)).join('|')
      }
    }

    return ({
      Method: route.method.toUpperCase(),
      Path: route.path,
      Auth: AUTH_MAP[auth] || AUTH_MAP[''],
      Access: scope,
      Controller: controller,
      Function: fn
    })
  })

  // Sort before formatting
  _routes.sort((a, b) => {
    if (a.Controller > b.Controller) return 1
    if (a.Controller < b.Controller) return -1

    if (a.Path > b.Path) return 1
    if (a.Path < b.Path) return -1

    let aI = METHODS.indexOf(a.Method)
    let bI = METHODS.indexOf(b.Method)
    if (aI > bI) return 1
    if (aI < bI) return -1

    return 0
  })

  // Colorize
  // let _counter = 0;
  _routes.forEach((route) => {
    const m = route.Method
    route.Method = `[ ${Chalk(method_color(m))} ]`
    route.Path = method_color(m, route.Path)

    // route.Controller = controller_color(route.Controller);
    route.Function = Chalk.grey(route.Function)
  })

  // Separate by controller
  let groupedRoutes = _.groupBy(_routes, 'Controller')
  _routes.forEach(r => {
    delete r.Controller
  })

  let groupedArray = []
  Object.keys(groupedRoutes).forEach(controller => {
    if (controller[0] === '_') {
      return
    }
    groupedArray.push(null)
    groupedArray.push(controller)
    groupedArray.push(null)
    groupedArray = groupedArray.concat(groupedRoutes[controller])
  })

  Utils.table.printTable(groupedArray, 'llccl', null, { indent: 0, rowSpace: 1 })

  console.log()
}

const RoutesPlugin = {
  register (server, config, next) {
    // Print routes table on server start for each connection
    server.ext('onPostStart', (_server, _next) => {
      _server.table().forEach(connection => {
        print_route_table(connection.table)
      })
      _next()
    })

    // Next
    if (next) next()
  }
}

RoutesPlugin.register.attributes = {
  name: 'bak-routes'
}

module.exports = RoutesPlugin
<commit_msg>remove routes.js<commit_after><|endoftext|>


<commit_before>'use strict';

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

module.exports = function(proto) {
  var define = require('define-property');

  /**
   * Add `Router` and `Route` to the prototype
   */

  proto.Router = utils.router.Router;
  proto.Route = utils.router.Route;

  /**
   * Lazily initalize `router`, to allow options to
   * be passed in after init.
   */

  proto.lazyRouter = function(methods) {
    if (typeof this.router === 'undefined') {
      this.define('router', new this.Router({
        methods: utils.methods
      }));
    }
    if (typeof methods !== 'undefined') {
      this.router.method(methods);
    }
  };

  /**
   * Handle a middleware `method` for `view`.
   *
   * ```js
   * app.handle('customMethod', view, callback);
   * ```
   * @name .handle
   * @param {String} `method` Name of the router method to handle. See [router methods](./docs/router.md)
   * @param {Object} `view` View object
   * @param {Function} `callback` Callback function
   * @return {Object}
   * @api public
   */

  proto.handle = function(method, view, locals, next) {
    this.debug.routes('handling method "%s", for view "%s"', method, view.key);

    if (typeof locals === 'function') {
      next = locals;
      locals = {};
    }

    this.lazyRouter();
    if (!view.options.handled) {
      view.options.handled = [];
    }

    var done = this.handleError(method, view, next);
    view.options.method = method;
    view.options.handled.push(method);
    this.emit(method, view);

    // if inside a collection or the collection is not specified on view.options
    // just handle the route and return
    if (!(this.isApp && view.options.collection)) {
      this.router.handle(view, done);
      return;
    }

    // handle the collection routes first, then handle the app routes
    var collection = this[view.options.collection];

    collection.handle(method, view, function(err) {
      if (err) return done(err);
      this.router.handle(view, done);
    }.bind(this));
  };

  /**
   * Run the given middleware handler only if the view has not
   * already been handled by the method.
   *
   * @name .handleOnce
   * @param  {Object} `method`
   * @param  {Object} `view`
   * @param  {Object} `locals`
   */

  proto.handleOnce = function(method, view, cb) {
    if (!view.options.handled) {
      view.options.handled = [];
    }

    if (view.options.handled.indexOf(method) === -1) {
      this.handle(method, view, cb);
      return;
    }

    if (typeof cb === 'function') {
      cb(null, view);
    }
  };

  /**
   * Deprecated, use `.handleOnce`
   *
   * @api public
   */

  proto.handleView = function() {
    console.log('.handleView is deprecated, use .handleOnce instead.');
    return this.handleOnce.apply(this, arguments);
  };

  /**
   * Handle middleware errors.
   */

  proto.handleError = function(method, view, cb) {
    if (typeof cb !== 'function') {
      cb = utils.identity;
    }
    var app = this;
    return function(err) {
      if (err) {
        if (err._handled) return cb();
        define(err, '_handled', true);
        err.source = err.stack.split('\n')[1].trim();
        err.reason = app._name + '#handle("' + method + '"): ' + view.path;
        app.emit('error', err);
        return cb(err);
      }
      cb(null, view);
    };
  };

  /**
   * Create a new Route for the given path. Each route contains
   * a separate middleware stack.
   *
   * See the [route API documentation][route-api] for details on
   * adding handlers and middleware to routes.
   *
   * ```js
   * app.create('posts');
   * app.route(/blog/)
   *   .all(function(view, next) {
   *     // do something with view
   *     next();
   *   });
   *
   * app.post('whatever', {path: 'blog/foo.bar', content: 'bar baz'});
   * ```
   * @name .route
   * @param {String} `path`
   * @return {Object} `Route` for chaining
   * @api public
   */

  proto.route = function(/*path*/) {
    this.lazyRouter();
    return this.router.route.apply(this.router, arguments);
  };

  /**
   * Special route method that works just like the `router.METHOD()`
   * methods, except that it matches all verbs.
   *
   * ```js
   * app.all(/\.hbs$/, function(view, next) {
   *   // do stuff to view
   *   next();
   * });
   * ```
   * @name .all
   * @param {String} `path`
   * @param {Function} `callback`
   * @return {Object} `this` for chaining
   * @api public
   */

  proto.all = function(path/*, callback*/) {
    var route = this.route(path);
    route.all.apply(route, [].slice.call(arguments, 1));
    return this;
  };

  /**
   * Add callback triggers to route parameters, where
   * `name` is the name of the parameter and `fn` is the
   * callback function.
   *
   * ```js
   * app.param('title', function(view, next, title) {
   *   //=> title === 'foo.js'
   *   next();
   * });
   *
   * app.onLoad('/blog/:title', function(view, next) {
   *   //=> view.path === '/blog/foo.js'
   *   next();
   * });
   * ```
   * @name .param
   * @param {String} `name`
   * @param {Function} `fn`
   * @return {Object} Returns the instance of `Templates` for chaining.
   * @api public
   */

  proto.param = function(/*name, fn*/) {
    this.lazyRouter();
    this.router.param.apply(this.router, arguments);
    return this;
  };

  /**
   * Add a router handler.
   *
   * @param  {String} `method` Method name.
   */

  proto.handler = function(methods) {
    this.handlers(methods);
  };

  /**
   * Add default Router handlers to Templates.
   */

  proto.handlers = function(methods) {
    this.lazyRouter(methods);

    utils.arrayify(methods).forEach(function(method) {
      this.define(method, function(path) {
        var route = this.route(path);
        var args = [].slice.call(arguments, 1);
        route[method].apply(route, args);
        return this;
      }.bind(this));
    }.bind(this));
  };

  // Add router methods to Templates
  utils.methods.forEach(function(method) {
    proto[method] = function(path) {
      var route = this.route(path);
      var args = [].slice.call(arguments, 1);
      route[method].apply(route, args);
      return this;
    };
  });
};

<commit_msg>handle app routes before handling collection routes this is mainly to ensure global handlers like parsing frontmatter are done before more specific collection middleware is handled on a collection<commit_after>'use strict';

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

module.exports = function(proto) {
  var define = require('define-property');

  /**
   * Add `Router` and `Route` to the prototype
   */

  proto.Router = utils.router.Router;
  proto.Route = utils.router.Route;

  /**
   * Lazily initalize `router`, to allow options to
   * be passed in after init.
   */

  proto.lazyRouter = function(methods) {
    if (typeof this.router === 'undefined') {
      this.define('router', new this.Router({
        methods: utils.methods
      }));
    }
    if (typeof methods !== 'undefined') {
      this.router.method(methods);
    }
  };

  /**
   * Handle a middleware `method` for `view`.
   *
   * ```js
   * app.handle('customMethod', view, callback);
   * ```
   * @name .handle
   * @param {String} `method` Name of the router method to handle. See [router methods](./docs/router.md)
   * @param {Object} `view` View object
   * @param {Function} `callback` Callback function
   * @return {Object}
   * @api public
   */

  proto.handle = function(method, view, locals, next) {
    this.debug.routes('handling method "%s", for view "%s"', method, view.key);

    if (typeof locals === 'function') {
      next = locals;
      locals = {};
    }

    this.lazyRouter();
    if (!view.options.handled) {
      view.options.handled = [];
    }

    var done = this.handleError(method, view, next);
    view.options.method = method;
    view.options.handled.push(method);
    this.emit(method, view);

    // if inside a collection or the collection is not specified on view.options
    // just handle the route and return
    if (!(this.isApp && view.options.collection)) {
      this.router.handle(view, done);
      return;
    }

    // handle the app routes first, then handle the collection routes
    var collection = this[view.options.collection];

    this.router.handle(view, function(err) {;
      if (err) return done(err);
      collection.handle(method, view, done);
    });
  };

  /**
   * Run the given middleware handler only if the view has not
   * already been handled by the method.
   *
   * @name .handleOnce
   * @param  {Object} `method`
   * @param  {Object} `view`
   * @param  {Object} `locals`
   */

  proto.handleOnce = function(method, view, cb) {
    if (!view.options.handled) {
      view.options.handled = [];
    }

    if (view.options.handled.indexOf(method) === -1) {
      this.handle(method, view, cb);
      return;
    }

    if (typeof cb === 'function') {
      cb(null, view);
    }
  };

  /**
   * Deprecated, use `.handleOnce`
   *
   * @api public
   */

  proto.handleView = function() {
    console.log('.handleView is deprecated, use .handleOnce instead.');
    return this.handleOnce.apply(this, arguments);
  };

  /**
   * Handle middleware errors.
   */

  proto.handleError = function(method, view, cb) {
    if (typeof cb !== 'function') {
      cb = utils.identity;
    }
    var app = this;
    return function(err) {
      if (err) {
        if (err._handled) return cb();
        define(err, '_handled', true);
        err.source = err.stack.split('\n')[1].trim();
        err.reason = app._name + '#handle("' + method + '"): ' + view.path;
        app.emit('error', err);
        return cb(err);
      }
      cb(null, view);
    };
  };

  /**
   * Create a new Route for the given path. Each route contains
   * a separate middleware stack.
   *
   * See the [route API documentation][route-api] for details on
   * adding handlers and middleware to routes.
   *
   * ```js
   * app.create('posts');
   * app.route(/blog/)
   *   .all(function(view, next) {
   *     // do something with view
   *     next();
   *   });
   *
   * app.post('whatever', {path: 'blog/foo.bar', content: 'bar baz'});
   * ```
   * @name .route
   * @param {String} `path`
   * @return {Object} `Route` for chaining
   * @api public
   */

  proto.route = function(/*path*/) {
    this.lazyRouter();
    return this.router.route.apply(this.router, arguments);
  };

  /**
   * Special route method that works just like the `router.METHOD()`
   * methods, except that it matches all verbs.
   *
   * ```js
   * app.all(/\.hbs$/, function(view, next) {
   *   // do stuff to view
   *   next();
   * });
   * ```
   * @name .all
   * @param {String} `path`
   * @param {Function} `callback`
   * @return {Object} `this` for chaining
   * @api public
   */

  proto.all = function(path/*, callback*/) {
    var route = this.route(path);
    route.all.apply(route, [].slice.call(arguments, 1));
    return this;
  };

  /**
   * Add callback triggers to route parameters, where
   * `name` is the name of the parameter and `fn` is the
   * callback function.
   *
   * ```js
   * app.param('title', function(view, next, title) {
   *   //=> title === 'foo.js'
   *   next();
   * });
   *
   * app.onLoad('/blog/:title', function(view, next) {
   *   //=> view.path === '/blog/foo.js'
   *   next();
   * });
   * ```
   * @name .param
   * @param {String} `name`
   * @param {Function} `fn`
   * @return {Object} Returns the instance of `Templates` for chaining.
   * @api public
   */

  proto.param = function(/*name, fn*/) {
    this.lazyRouter();
    this.router.param.apply(this.router, arguments);
    return this;
  };

  /**
   * Add a router handler.
   *
   * @param  {String} `method` Method name.
   */

  proto.handler = function(methods) {
    this.handlers(methods);
  };

  /**
   * Add default Router handlers to Templates.
   */

  proto.handlers = function(methods) {
    this.lazyRouter(methods);

    utils.arrayify(methods).forEach(function(method) {
      this.define(method, function(path) {
        var route = this.route(path);
        var args = [].slice.call(arguments, 1);
        route[method].apply(route, args);
        return this;
      }.bind(this));
    }.bind(this));
  };

  // Add router methods to Templates
  utils.methods.forEach(function(method) {
    proto[method] = function(path) {
      var route = this.route(path);
      var args = [].slice.call(arguments, 1);
      route[method].apply(route, args);
      return this;
    };
  });
};

<|endoftext|>


<commit_before>var env = process.env;
var gzip = require('zlib').gzip;
var cache = require(env.Z_PATH_CACHE + 'cache');
var client;
var libs;
var resHeaders = {
    'Cache-Control': 'public, max-age=31536000',
    'Vary': 'Accept-Encoding',
    'Content-Type': 'text/html; charset=utf-8',
    'Content-Encoding': 'gzip'
};

var publicCache = cache.pojo('public');

// get libs array
if (env.Z_LIBS) {
    libs = JSON.parse(env.Z_LIBS);
}

function sendClient (res) {

    if (client) {
        res.writeHead(200, resHeaders);
        return res.end(client);
    }

    var lib_src = '';
    if (libs) {
        for (var i = 0; i < libs.length; ++i) {
            lib_src += "\n";
        }
    }

    gzip(
        "<!DOCTYPE html><link rel='icon' href='/favicon.ico'/>" +
        "" +
            lib_src +
            "" +
        "",
        function (err, data) {

            client = data;
            resHeaders['Content-Length'] = client.length;
            res.writeHead(200, resHeaders);
            res.end(client);
        }
    );
}

function route (pathname, req, res) {
    var self = this;

    // send client
    if (pathname === '/') {
        return sendClient(res);
    }

    pathname = env.Z_PATH_PROCESS_PUBLIC + pathname;

    var file = publicCache.get(pathname);
    if (file) {
        res.writeHead(200, file.http);
        return res.end(file.data);
    }

    publicCache.set(pathname, function (err, file) {

        if (err) {
            return sendClient(res);
        }

        res.writeHead(200, file.http);
        res.end(file.data);
    });
}

module.exports = route;
<commit_msg>use file cache for public files<commit_after>var env = process.env;
var gzip = require('zlib').gzip;
var cache = require(env.Z_PATH_CACHE + 'cache');
var client;
var libs;
var resHeaders = {
    'Cache-Control': 'public, max-age=31536000',
    'Vary': 'Accept-Encoding',
    'Content-Type': 'text/html; charset=utf-8',
    'Content-Encoding': 'gzip'
};

var publicCache = cache.file('public');

// get libs array
if (env.Z_LIBS) {
    libs = JSON.parse(env.Z_LIBS);
}

function sendClient (res) {

    if (client) {
        res.writeHead(200, resHeaders);
        return res.end(client);
    }

    var lib_src = '';
    if (libs) {
        for (var i = 0; i < libs.length; ++i) {
            lib_src += "\n";
        }
    }

    gzip(
        "<!DOCTYPE html><link rel='icon' href='/favicon.ico'/>" +
        "" +
            lib_src +
            "" +
        "",
        function (err, data) {

            client = data;
            resHeaders['Content-Length'] = client.length;
            res.writeHead(200, resHeaders);
            res.end(client);
        }
    );
}

function route (pathname, req, res) {
    var self = this;

    // send client
    if (pathname === '/') {
        return sendClient(res);
    }

    pathname = env.Z_PATH_PROCESS_PUBLIC + pathname;

    var file = publicCache.get(pathname);
    if (file) {
        res.writeHead(200, file.http);
        res.end(file.data);
        return;
    }

    publicCache.set(pathname, function (err, file) {

        if (err) {
            return sendClient(res);
        }

        res.writeHead(200, file.http);
        res.end(file.data);
    });
}

module.exports = route;
<|endoftext|>


<commit_before>'use strict'

// **Module exports set of of utility functions that are useful for working
// with promises.**

var Q = require('q'), when = Q.when, defer = Q.defer

,   _slice = Array.prototype.slice
,   _forEach = Array.prototype.forEach

// ## all ##
// Function takes array of promises and gives a new promise in return which will
// be fulfilled with an array of resolved promises that where passed. If any of
// the passed promises will get rejected, rejection will be forwarded to a
// returned promise.
/**
 * Creates promise for array of the promises that is resolved with an array
 * of the promise resolutions.
 * @param {Promise[]} promises
 *    Array of promises to create promise for.
 */
function all(promises) {
  var l = promises.length
  ,   values = []
  // If empty array is passed to the function it is returned immediately.
  if (0 == l) return values
  var deferred = defer()
  // Listeners are set for all the promises that where passed.
  _forEach.call(promises, function(promise, index) {
    when
    ( promise
    , function resolved(value) {
        // Resolved promises are stored in the array in the same exact order as
        // they where passed to the function.
        values[index] = value
        // If all the observed promises are resolved resulting promise is
        // resolved with an array of resolved promises.
        if (0 === --l) deferred.resolve(values)
      }
      // If for some reason one of the promises is rejected, resulting promise
      // is rejected with a same reason.
    , function rejected(reason) { deferred.reject(reason) }
    )
  })
  return deferred.promise
}
// **Example:**
//
//      var Q = require('q'), when = Q.when, defer = Q.defer
//      var all = require('promised-utils').all
//
//      var d1 = defer(), d2 = defer(), d3 = defer()
//      when
//      ( all([d1.promise, d2.promise, d3.promise])
//      , function resolved(values) {
//          var result = 0
//          values.forEach(function(value) { result += value })
//          console.log(result)
//        }
//      , function rejected(reason) { console.error(reason) }
//      )
//
//      d1.resolve(2)
//      d2.resolve(100)
//      d3.resolve(15)
//
//      // > 117
//
//
exports.all = all

// ## Promised ##
// Function takes function as an argument. Optional second argument can be
// passed with a truthy value to make clear that function passed as a first
// argument is synchronous.
/**
 * @param {Function} callee
 * @returns {Promise}
 */
function Promised(callee, sync) {
  // Passed function is wrapped into another, so called promised function, that
  // is returned as a result.
  return function promised() {
    // Returned function always returns a new promise when called.
    var deferred = defer()
    ,   reject = Reject(deferred, callee)
    // It also assumes that all of the arguments passed to it represent
    // promises.
    ,   possiblyPromises = _slice.call(arguments, 0)
    // In addition `this` pseudo-variable is also assumed to be a promise.
    possiblyPromises.unshift(this)
    // When all the possible promises are resolved, wrapped function is called
    when
    ( all(possiblyPromises)
    // It is called with resolved promises as an arguments.
    , function possiblePromisesResolved(params) {
        try {
          // If wrapped function was not identified as synchronous one
          // additional argument, callback function is passed to it.
          if (!sync) params.push(Callback(deferred))
          // Resolved `this` pseudo-variable is passed along.
          var value = callee.call.apply(callee, params)
          // If value returned by wrapped function was different from
          // `undefined` or function was identified as synchronous returned
          // promise will be resolved with it. Otherwise it will be rejected
          // or resolved when additional callback function is invoked. If first
          // argument to a callback function will be non-falsy promise will be
          // rejected with it, in opposite case promise will be resolved as
          // a second argument.
          if (sync || undefined !== value) deferred.resolve(value)
        } catch(error) {
          // If exception is thrown by wrapper function returned promise is
          // rejected with it.
          reject(error)
        }
      }
      // If for some reason one of the promises gets rejected, returned promise
      // will be rejected with same reason, but with additional details.
    , reject
    )
    return deferred.promise
  }
}
// **Example:**
//
//      var Q = require('q'), when = Q.when, defer = Q.defer
//      var Promised = require('promised-utils').Promised
//
//      var promisedSum = Promised(function sum(a, b) {
//        return a + b
//      })
//
//      var a = defer(), b = defer()
//      when(promisedSum(a.promise, b.promise), console.log, console.error)
//
//      a.resolve(2)
//      b.resolve(3)
//
//      // > 5
//
exports.Promised = Promised
// ### Promised.async ###
// At the moment functions wrapped by `Promised` are assumed to by asynchronous
// and they are called with additional callback argument. This assumption may
// change in a future version and this function can be used to explicitly
// highlight that passed function is synchronous and it expects to get
// a callback as a last argument.
Promised.async = Promised
// ### Promised.sync ###
// As it was mentioned above `Promised` function assumes that functions passed
// to it are asynchronous and they will be called with an extra callback
// argument. This will work just fine in many cases, but not in cases where
// wrapped function expects unlimited amount of arguments and does not performs
// any checks on them.
Promised.sync = function syncPromised(callee) {
  return Promised(callee, true)
}
// **Example:**
//
//      var Q = require('q'), when = Q.when, defer = Q.defer
//      var Promised = require('promised-utils').Promised
//
//      var promisedConcat = Promised.sync(String.prototype.concat.bind(''))
//      var d = defer()
//      var promisedString = promisedConcat('Hello ', d.promise)
//      when(promisedString, console.log) // will print Hello World
//      d.resolve('World')

// ## Reject ##
// Function takes deferred promise and function performing operation that may
// throw an exception that should result in rejection of promise.
function Reject(deferred, callee) {
  // Callback function is returned as a result value.
  return function reject(reason) {
    // If callback is called wrapped promise is rejected with:
    deferred.reject(
    // - Function name containing logic.
    { at: callee.name
    // - Reason (thrown exception or string)
    , cause: reason
    // - Error stack trace
    , stack: new Error(callee.name).stack
    })
  }
}
// ## Callback ##
// Function takes deferred promise and returns [node.js](http://nodejs.org/)
// style callback function.
/**
 * @param {Deferred}
 * @returns {Function}
 */
function Callback(deferred) {
  return function callback(error, value) {
    // If returned callback is called with first non-falsy argument,
    // wrapped promise is rejected with it.
    if (error) deferred.reject(error)
    // Otherwise promise is resolved with a value of a second argument.
    else deferred.resolve(value)
  }
}
exports.Callback = Callback
// **Example:**
//
//      var Callback = require('promised-utils').Callback
//      ,   q = require('q'), when = q.when, defer = q.defer
//
//      function promisedReadFile(path) {
//        var deferred = defer()
//        require('fs').readFile(Callback(deferred))
//        return deferred
//      }
<commit_msg>Adding ability to create Promised(object) that exposes following APIs:<commit_after>'use strict'

// **Module exports set of of utility functions that are useful for working
// with promises.**

var Q = require('q'), when = Q.when, defer = Q.defer, Get = Q.get, Set = Q.set, Post = Q.post

,   _slice = Array.prototype.slice
,   _forEach = Array.prototype.forEach

// ## all ##
// Function takes array of promises and gives a new promise in return which will
// be fulfilled with an array of resolved promises that where passed. If any of
// the passed promises will get rejected, rejection will be forwarded to a
// returned promise.
/**
 * Creates promise for array of the promises that is resolved with an array
 * of the promise resolutions.
 * @param {Promise[]} promises
 *    Array of promises to create promise for.
 */
function all(promises) {
  var l = promises.length
  ,   values = []
  // If empty array is passed to the function it is returned immediately.
  if (0 == l) return values
  var deferred = defer()
  // Listeners are set for all the promises that where passed.
  _forEach.call(promises, function(promise, index) {
    when
    ( promise
    , function resolved(value) {
        // Resolved promises are stored in the array in the same exact order as
        // they where passed to the function.
        values[index] = value
        // If all the observed promises are resolved resulting promise is
        // resolved with an array of resolved promises.
        if (0 === --l) deferred.resolve(values)
      }
      // If for some reason one of the promises is rejected, resulting promise
      // is rejected with a same reason.
    , function rejected(reason) { deferred.reject(reason) }
    )
  })
  return deferred.promise
}
// **Example:**
//
//      var Q = require('q'), when = Q.when, defer = Q.defer
//      var all = require('promised-utils').all
//
//      var d1 = defer(), d2 = defer(), d3 = defer()
//      when
//      ( all([d1.promise, d2.promise, d3.promise])
//      , function resolved(values) {
//          var result = 0
//          values.forEach(function(value) { result += value })
//          console.log(result)
//        }
//      , function rejected(reason) { console.error(reason) }
//      )
//
//      d1.resolve(2)
//      d2.resolve(100)
//      d3.resolve(15)
//
//      // > 117
//
//
exports.all = all

// ## Promised ##
// Function takes function as an argument. Optional second argument can be
// passed with a truthy value to make clear that function passed as a first
// argument is synchronous.
/**
 * @param {Function} callee
 * @returns {Promise}
 */
function Promised(callee, sync) {
  if ('object' == typeof callee) return Object.create(when(callee), DPromised)
  // Passed function is wrapped into another, so called promised function, that
  // is returned as a result.
  return function promised() {
    // Returned function always returns a new promise when called.
    var deferred = defer()
    ,   reject = Reject(deferred, callee)
    // It also assumes that all of the arguments passed to it represent
    // promises.
    ,   possiblyPromises = _slice.call(arguments, 0)
    // In addition `this` pseudo-variable is also assumed to be a promise.
    possiblyPromises.unshift(this)
    // When all the possible promises are resolved, wrapped function is called
    when
    ( all(possiblyPromises)
    // It is called with resolved promises as an arguments.
    , function possiblePromisesResolved(params) {
        try {
          // If wrapped function was not identified as synchronous one
          // additional argument, callback function is passed to it.
          if (!sync) params.push(Callback(deferred))
          // Resolved `this` pseudo-variable is passed along.
          var value = callee.call.apply(callee, params)
          // If value returned by wrapped function was different from
          // `undefined` or function was identified as synchronous returned
          // promise will be resolved with it. Otherwise it will be rejected
          // or resolved when additional callback function is invoked. If first
          // argument to a callback function will be non-falsy promise will be
          // rejected with it, in opposite case promise will be resolved as
          // a second argument.
          if (sync || undefined !== value) deferred.resolve(value)
        } catch(error) {
          // If exception is thrown by wrapper function returned promise is
          // rejected with it.
          reject(error)
        }
      }
      // If for some reason one of the promises gets rejected, returned promise
      // will be rejected with same reason, but with additional details.
    , reject
    )
    return deferred.promise
  }
}
// **Example:**
//
//      var Q = require('q'), when = Q.when, defer = Q.defer
//      var Promised = require('promised-utils').Promised
//
//      var promisedSum = Promised(function sum(a, b) {
//        return a + b
//      })
//
//      var a = defer(), b = defer()
//      when(promisedSum(a.promise, b.promise), console.log, console.error)
//
//      a.resolve(2)
//      b.resolve(3)
//
//      // > 5
//
exports.Promised = Promised
// ### Promised.async ###
// At the moment functions wrapped by `Promised` are assumed to by asynchronous
// and they are called with additional callback argument. This assumption may
// change in a future version and this function can be used to explicitly
// highlight that passed function is synchronous and it expects to get
// a callback as a last argument.
Promised.async = Promised
// ### Promised.sync ###
// As it was mentioned above `Promised` function assumes that functions passed
// to it are asynchronous and they will be called with an extra callback
// argument. This will work just fine in many cases, but not in cases where
// wrapped function expects unlimited amount of arguments and does not performs
// any checks on them.
Promised.sync = function syncPromised(callee) {
  return Promised(callee, true)
}
// **Example:**
//
//      var Q = require('q'), when = Q.when, defer = Q.defer
//      var Promised = require('promised-utils').Promised
//
//      var promisedConcat = Promised.sync(String.prototype.concat.bind(''))
//      var d = defer()
//      var promisedString = promisedConcat('Hello ', d.promise)
//      when(promisedString, console.log) // will print Hello World
//      d.resolve('World')

// ## Reject ##
// Function takes deferred promise and function performing operation that may
// throw an exception that should result in rejection of promise.
function Reject(deferred, callee) {
  // Callback function is returned as a result value.
  return function reject(reason) {
    // If callback is called wrapped promise is rejected with:
    deferred.reject(
    // - Function name containing logic.
    { at: callee.name
    // - Reason (thrown exception or string)
    , cause: reason
    // - Error stack trace
    , stack: new Error(callee.name).stack
    })
  }
}
// ## Callback ##
// Function takes deferred promise and returns [node.js](http://nodejs.org/)
// style callback function.
/**
 * @param {Deferred}
 * @returns {Function}
 */
function Callback(deferred) {
  return function callback(error, value) {
    // If returned callback is called with first non-falsy argument,
    // wrapped promise is rejected with it.
    if (error) deferred.reject(error)
    // Otherwise promise is resolved with a value of a second argument.
    else deferred.resolve(value)
  }
}
exports.Callback = Callback
// **Example:**
//
//      var Callback = require('promised-utils').Callback
//      ,   q = require('q'), when = q.when, defer = q.defer
//
//      function promisedReadFile(path) {
//        var deferred = defer()
//        require('fs').readFile(Callback(deferred))
//        return deferred
//      }

var DPromised =
{ get: { value: function get(path) {
    return Object.create(String(path).split('.').reduce(Get, this), DPromised)
  }}
, set: { value: function set(path, value) {
    path = String(path).split('.')
    var name = path.pop()
    return Object.create(Q.put(path.reduce(Get, this), name, value))
  }}
, invoke: { value: function invoke(path, params) {
    path = String(path).split('.')
    var name = path.pop()
    ,   target = path.reduce(Get, this)
    return params ? Object.create(when(all(params), function onParams(params) {
      return Post(target, name, params)
    }, DPromised)) : Object.create(Post(target, name), DPromised)
  }}
}

exports.print = Promised.sync(console.log.bind(console))
<|endoftext|>


<commit_before>/**
 *
 * reset an app
 *
 * @see  https://github.com/appium/appium/blob/master/docs/en/appium-bindings.md#reset
 * @type mobile
 * @for android
 *
 */

let resetApp = function () {
    return this.requestHandler.create({
        path: '/session/:sessionId/appium/app/reset',
        method: 'POST'
    })
}

export default resetApp
<commit_msg>renamed resetApp to reset, improved docs<commit_after>/**
 *
 * Reset the device.
 *
 * @see  https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/appium-bindings.md#reset
 * @type mobile
 * @for android
 *
 */

let reset = function () {
    return this.requestHandler.create({
        path: '/session/:sessionId/appium/app/reset',
        method: 'POST'
    })
}

export default reset
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var util = require('util'),
    Base = require('./base'),
    fs = require('fs'),
    path = require('path'),
    sanitizeCaps = require('../helpers/sanitize').caps;

/**
 * Initialize a new `XUnit` reporter.
 *
 * @param {Runner} runner
 * @api public
 */
function XUnit(options) {
    Base.call(this);

    var tests = this.tests = {},
        runnerData = this.runnerData = {},
        self = this,
        id = 0;

    this.errorLogCharacterLimitation = 10000;
    this.indents = 0;
    this.errors = 0;
    this.options = options;

    /**
     * remember which tests got executed by runner
     */
    this.on('runner:start', function(runner) {
        tests[runner.pid] = [{
            start: new Date(),
            tests: [],
            root: true,
            /**
             * problematic by setting end date when runner started:
             * `<testsuites />` time will include computation time of all before/after hooks, that
             * results in a bigger time value then all time values of its `<testsuite/>` summed
             * together
             */
            end: new Date(),
        }];

        runnerData[runner.pid] = {
            command: [],
            result: [],
            error: []
        };
    });

    this.on('runner:command', function(data) {
        runnerData[data.pid].command.push(data);
    });
    this.on('runner:result', function(data) {
        runnerData[data.pid].result.push(data);
    });
    this.on('runner:error', function(data) {
        self.errors++;
        runnerData[data.pid].error.push(data);
    });

    /**
     * clear runnerData cache
     */
    this.on('test:start', function(test) {
        runnerData[test.pid] = {
            command: [],
            result: [],
            error: []
        };
    });

    this.on('suite:start', function(suite){
        suite.id = ++id;
        suite.tests = [];
        suite.passes = 0;
        suite.pending = 0;
        suite.failures = 0;
        suite.timestamp = new Date();

        /**
         * root suites
         */
        if(suite.parent === '' || !suite.parent) {
            tests[suite.pid][0].tests.push(suite);
            return;
        }

        var parentSuite = this.findParentSuite(suite.parent, this.tests[suite.pid][0]);
        parentSuite.tests.push(suite);
    });

    this.on('test:pending', function(test) {
        var parentSuite = this.findParentSuite(test.parent, this.tests[test.pid][0]);
        parentSuite.pending++;
        test.id = ++id;
        test.time = new Date() - tests[test.pid][0].end,
        test.timestamp = tests[test.pid][0].end = new Date();
        test.runnerData = runnerData[test.pid];
        parentSuite.tests.push(test);
    });

    this.on('test:pass', function(test) {
        var parentSuite = this.findParentSuite(test.parent, this.tests[test.pid][0]);
        parentSuite.passes++;
        test.id = ++id;
        test.time = new Date() - tests[test.pid][0].end,
        test.timestamp = tests[test.pid][0].end = new Date();
        test.runnerData = runnerData[test.pid];
        parentSuite.tests.push(test);
    });

    this.on('test:fail', function(test) {
        var parentSuite = this.findParentSuite(test.parent, this.tests[test.pid][0]);
        parentSuite.failures++;
        test.id = ++id;
        test.time = new Date() - tests[test.pid][0].end,
        test.timestamp = tests[test.pid][0].end = new Date();
        test.runnerData = runnerData[test.pid];
        parentSuite.tests.push(test);
    });

    this.on('end', function() {
        Object.keys(tests).forEach(function(pid) {
            self.genTestsuites(tests[pid], pid);
        });
    });
}

/**
 * Inherit from Base
 */
util.inherits(XUnit, Base);

function escape(html){
  return String(html)
    .replace(/&/g, '&')
    .replace(/"/g, '"')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/\r?\n|\r/g, '');
}

XUnit.prototype.findParentSuite = function(title, suite) {
    var _suite = null;

    for(var i = 0; i < suite.tests.length; ++i) {
        if(suite.tests[i].title === title) {
            return suite.tests[i];
        }

        if(suite.tests[i].tests) {
            _suite = _suite || this.findParentSuite(title, suite.tests[i]);
        }
    }

    return _suite;
};

/**
 * generate junit report
 */
XUnit.prototype.genTestsuites = function(tests, pid) {

    var caps = this.stats.runner[pid].capabilities,
        options = this.options.reporterOptions,
        filename = 'WDIO.xunit.' + sanitizeCaps(caps) + '.' + pid + '.xml';

    if (options && typeof options.outputDir === 'string') {
        this.fileStream = fs.createWriteStream(path.join(process.cwd(), options.outputDir, filename));
    }

    /**
     * root testsuites tag
     */
    this.write(tag('testsuites', {
        name: sanitizeCaps(caps),
        tests: this.stats.tests,
        failures: this.stats.failures,
        errors: this.errors,
        disabled: this.stats.pending,
        time: this.stats.duration / 1000
    }));

    this.indents++;
    this.genTestsuite(tests[0].tests);
    this.indents--;

    this.write('</testsuites>');

    if (this.fileStream) {
        this.fileStream.end();
    }
};

function sumTime(suite) {
    var res = 0;

    for(var i = 0; i < suite.tests.length; ++i) {
        if(suite.tests[i].tests) {
            res += sumTime(suite.tests[i]);
        } else {
            res += suite.tests[i].time;
        }
    }

    return res;
}

XUnit.prototype.printLogTags = function(data, tagName, type, iter) {
    var content = '';

    for(var i = 0; i < data.length; ++i) {
        content += iter(data[i]);
    }

    if(content !== '') {
        content = cdata('\n' + content);
        this.indents++;
        this.write(tag(tagName, {
            type: type
        }, false, content));
        this.indents--;
    }
};

/**
 * generate testsuites markup
 */
XUnit.prototype.genTestsuite = function(tests) {

    var self = this;

    tests.forEach(function(test) {

        /**
         * write test suite
         */
        if(test.tests) {
            self.write(tag('testsuite', {
                name: test.title,
                tests: test.pending + test.passes + test.failures,
                failures: test.failures,
                // errors: test.failures,
                skipped: test.pending,
                disabled: test.pending,
                time: sumTime(test) / 1000,
                timestamp: test.timestamp,
                id: test.id,
                file: test.file
            }));

            self.indents++;
            self.genTestsuite(test.tests);
            self.indents--;

            self.write('</testsuite>');
            return;
        }

        /**
         * write testcase
         */
        self.write(tag('testcase', {
            name: test.title,
            disabled: test.pending,
            time: test.time / 1000,
            id: test.id,
            file: test.file,
            status: test.err ? 'failed' : 'passed',
            classname: sanitizeCaps(self.stats.runner[test.pid].capabilities)
        }));

        /**
         * print skipped tags
         */
        if(test.pending) {

            self.indents++;
            self.write(tag('skipped', {}, true));
            self.indents--;

            self.write('</testcase>');
            return;

        /**
         * print failure tags
         */
        } else if(test.err) {
            var content = cdata((test.err.stack || '').slice(0, self.errorLogCharacterLimitation));

            self.indents++;
            self.write(tag('failure', {
                type: 'testerror',
                message: escape(test.err.message)
            }, false, content));
            self.indents--;

        }

        /**
         * print runner logs
         */
        self.printLogTags(test.runnerData.command, 'system-out', 'command', function(data) {
            return data.method.toUpperCase() + ' ' + data.uri.href + ' - ' + JSON.stringify(data.data) + '\n';
        });
        self.printLogTags(test.runnerData.result, 'system-out', 'result', function(data) {
            return (data.requestOptions.method || 'get').toUpperCase() + ' ' + data.requestOptions.uri.href + ' - ' + JSON.stringify(data.body).slice(0, self.errorLogCharacterLimitation) + '\n';
        });
        self.printLogTags(test.runnerData.error, 'system-err', 'runnererror', function(data) {
            return (data.requestOptions.method || 'get').toUpperCase() + ' ' + data.requestOptions.uri.href + '\n' +
                   'ERROR:' + data.err + '\n' +
                   'BODY:' + (typeof data.body === 'object' ? JSON.stringify(data.body) : data.body).slice(0, self.errorLogCharacterLimitation) + '\n';
        });

        self.write('</testcase>');
    });

};

/**
 * Write out the given line
 */
XUnit.prototype.write = function(line) {
    var indent = Array(this.indents * 2).join('  ');
    if (this.fileStream) {
        this.fileStream.write(indent + line + '\n');
    } else {
        console.log(indent + line);
    }
};

/**
 * HTML tag helper.
 */
function tag(name, attrs, close, content) {
    var end = close ? '/>' : '>',
        pairs = [],
        _tag;

    for (var key in attrs) {
        pairs.push(key + '="' + escape(attrs[key]) + '"');
    }

    _tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
    if (content) _tag += content + '</' + name + end;
    return _tag;
}

/**
 * Return cdata escaped CDATA `str`.
 */

function cdata(str) {
    return '<![CDATA[' + str + ']]>';
}

/**
 * Expose `XUnit`.
 */
exports = module.exports = XUnit;<commit_msg>fixed xunit system-err output - closes #631 [ci skip]<commit_after>/**
 * Module dependencies.
 */

var util = require('util'),
    Base = require('./base'),
    fs = require('fs'),
    path = require('path'),
    sanitizeCaps = require('../helpers/sanitize').caps;

/**
 * Initialize a new `XUnit` reporter.
 *
 * @param {Runner} runner
 * @api public
 */
function XUnit(options) {
    Base.call(this);

    var tests = this.tests = {},
        runnerData = this.runnerData = {},
        self = this,
        id = 0;

    this.errorLogCharacterLimitation = 10000;
    this.indents = 0;
    this.errors = 0;
    this.options = options;

    /**
     * remember which tests got executed by runner
     */
    this.on('runner:start', function(runner) {
        tests[runner.pid] = [{
            start: new Date(),
            tests: [],
            root: true,
            /**
             * problematic by setting end date when runner started:
             * `<testsuites />` time will include computation time of all before/after hooks, that
             * results in a bigger time value then all time values of its `<testsuite/>` summed
             * together
             */
            end: new Date(),
        }];

        runnerData[runner.pid] = {
            command: [],
            result: [],
            error: []
        };
    });

    this.on('runner:command', function(data) {
        runnerData[data.pid].command.push(data);
    });
    this.on('runner:result', function(data) {
        runnerData[data.pid].result.push(data);
    });
    this.on('runner:error', function(data) {
        self.errors++;
        runnerData[data.pid].error.push(data);
    });

    /**
     * clear runnerData cache
     */
    this.on('test:start', function(test) {
        runnerData[test.pid] = {
            command: [],
            result: [],
            error: []
        };
    });

    this.on('suite:start', function(suite){
        suite.id = ++id;
        suite.tests = [];
        suite.passes = 0;
        suite.pending = 0;
        suite.failures = 0;
        suite.timestamp = new Date();

        /**
         * root suites
         */
        if(suite.parent === '' || !suite.parent) {
            tests[suite.pid][0].tests.push(suite);
            return;
        }

        var parentSuite = this.findParentSuite(suite.parent, this.tests[suite.pid][0]);
        parentSuite.tests.push(suite);
    });

    this.on('test:pending', function(test) {
        var parentSuite = this.findParentSuite(test.parent, this.tests[test.pid][0]);
        parentSuite.pending++;
        test.id = ++id;
        test.time = new Date() - tests[test.pid][0].end,
        test.timestamp = tests[test.pid][0].end = new Date();
        test.runnerData = runnerData[test.pid];
        parentSuite.tests.push(test);
    });

    this.on('test:pass', function(test) {
        var parentSuite = this.findParentSuite(test.parent, this.tests[test.pid][0]);
        parentSuite.passes++;
        test.id = ++id;
        test.time = new Date() - tests[test.pid][0].end,
        test.timestamp = tests[test.pid][0].end = new Date();
        test.runnerData = runnerData[test.pid];
        parentSuite.tests.push(test);
    });

    this.on('test:fail', function(test) {
        var parentSuite = this.findParentSuite(test.parent, this.tests[test.pid][0]);
        parentSuite.failures++;
        test.id = ++id;
        test.time = new Date() - tests[test.pid][0].end,
        test.timestamp = tests[test.pid][0].end = new Date();
        test.runnerData = runnerData[test.pid];
        parentSuite.tests.push(test);
    });

    this.on('end', function() {
        Object.keys(tests).forEach(function(pid) {
            self.genTestsuites(tests[pid], pid);
        });
    });
}

/**
 * Inherit from Base
 */
util.inherits(XUnit, Base);

function escape(html){
  return String(html)
    .replace(/&/g, '&')
    .replace(/"/g, '"')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/\r?\n|\r/g, '');
}

XUnit.prototype.findParentSuite = function(title, suite) {
    var _suite = null;

    for(var i = 0; i < suite.tests.length; ++i) {
        if(suite.tests[i].title === title) {
            return suite.tests[i];
        }

        if(suite.tests[i].tests) {
            _suite = _suite || this.findParentSuite(title, suite.tests[i]);
        }
    }

    return _suite;
};

/**
 * generate junit report
 */
XUnit.prototype.genTestsuites = function(tests, pid) {

    var caps = this.stats.runner[pid].capabilities,
        options = this.options.reporterOptions,
        filename = 'WDIO.xunit.' + sanitizeCaps(caps) + '.' + pid + '.xml';

    if (options && typeof options.outputDir === 'string') {
        this.fileStream = fs.createWriteStream(path.join(process.cwd(), options.outputDir, filename));
    }

    /**
     * root testsuites tag
     */
    this.write(tag('testsuites', {
        name: sanitizeCaps(caps),
        tests: this.stats.tests,
        failures: this.stats.failures,
        errors: this.errors,
        disabled: this.stats.pending,
        time: this.stats.duration / 1000
    }));

    this.indents++;
    this.genTestsuite(tests[0].tests);
    this.indents--;

    this.write('</testsuites>');

    if (this.fileStream) {
        this.fileStream.end();
    }
};

function sumTime(suite) {
    var res = 0;

    for(var i = 0; i < suite.tests.length; ++i) {
        if(suite.tests[i].tests) {
            res += sumTime(suite.tests[i]);
        } else {
            res += suite.tests[i].time;
        }
    }

    return res;
}

XUnit.prototype.printLogTags = function(data, tagName, type, iter) {
    var content = '';

    for(var i = 0; i < data.length; ++i) {
        content += iter(data[i]);
    }

    if(content !== '') {
        content = cdata('\n' + content);
        this.indents++;
        this.write(tag(tagName, {
            type: type
        }, false, content));
        this.indents--;
    }
};

/**
 * generate testsuites markup
 */
XUnit.prototype.genTestsuite = function(tests) {

    var self = this;

    tests.forEach(function(test) {

        /**
         * write test suite
         */
        if(test.tests) {
            self.write(tag('testsuite', {
                name: test.title,
                tests: test.pending + test.passes + test.failures,
                failures: test.failures,
                // errors: test.failures,
                skipped: test.pending,
                disabled: test.pending,
                time: sumTime(test) / 1000,
                timestamp: test.timestamp,
                id: test.id,
                file: test.file
            }));

            self.indents++;
            self.genTestsuite(test.tests);
            self.indents--;

            self.write('</testsuite>');
            return;
        }

        /**
         * write testcase
         */
        self.write(tag('testcase', {
            name: test.title,
            disabled: test.pending,
            time: test.time / 1000,
            id: test.id,
            file: test.file,
            status: test.err ? 'failed' : 'passed',
            classname: sanitizeCaps(self.stats.runner[test.pid].capabilities)
        }));

        /**
         * print skipped tags
         */
        if(test.pending) {

            self.indents++;
            self.write(tag('skipped', {}, true));
            self.indents--;

            self.write('</testcase>');
            return;

        /**
         * print failure tags
         */
        } else if(test.err) {
            var content = cdata((test.err.stack || '').slice(0, self.errorLogCharacterLimitation));

            self.indents++;
            self.write(tag('failure', {
                type: 'testerror',
                message: escape(test.err.message)
            }, false, content));
            self.indents--;

        }

        /**
         * print runner logs
         */
        self.printLogTags(test.runnerData.command, 'system-out', 'command', function(data) {
            return data.method.toUpperCase() + ' ' + data.uri.href + ' - ' + JSON.stringify(data.data) + '\n';
        });
        self.printLogTags(test.runnerData.result, 'system-out', 'result', function(data) {
            return (data.requestOptions.method || 'get').toUpperCase() + ' ' + data.requestOptions.uri.href + ' - ' + JSON.stringify(data.body).slice(0, self.errorLogCharacterLimitation) + '\n';
        });
        self.printLogTags(test.runnerData.error, 'system-err', 'runnererror', function(data) {
            var ret = '';

            if(data.requestOptions) {
                ret += (data.requestOptions.method || 'get').toUpperCase() + ' ' + data.requestOptions.uri.href + '\n';
            }

            ret += 'ERROR:' + data.err + '\n';

            if(data.body) {
                ret += 'BODY:' + (typeof data.body === 'object' ? JSON.stringify(data.body) : data.body).slice(0, self.errorLogCharacterLimitation) + '\n';
            }

            return ret;
        });

        self.write('</testcase>');
    });

};

/**
 * Write out the given line
 */
XUnit.prototype.write = function(line) {
    var indent = Array(this.indents * 2).join('  ');
    if (this.fileStream) {
        this.fileStream.write(indent + line + '\n');
    } else {
        console.log(indent + line);
    }
};

/**
 * HTML tag helper.
 */
function tag(name, attrs, close, content) {
    var end = close ? '/>' : '>',
        pairs = [],
        _tag;

    for (var key in attrs) {
        pairs.push(key + '="' + escape(attrs[key]) + '"');
    }

    _tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
    if (content) _tag += content + '</' + name + end;
    return _tag;
}

/**
 * Return cdata escaped CDATA `str`.
 */

function cdata(str) {
    return '<![CDATA[' + str + ']]>';
}

/**
 * Expose `XUnit`.
 */
exports = module.exports = XUnit;<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var tty = require('tty')
  , diff = require('diff')
  , ms = require('../ms');

/**
 * Save timer references to avoid Sinon interfering (see GH-237).
 */

var Date = global.Date
  , setTimeout = global.setTimeout
  , setInterval = global.setInterval
  , clearTimeout = global.clearTimeout
  , clearInterval = global.clearInterval;

/**
 * Check if both stdio streams are associated with a tty.
 */

var isatty = tty.isatty(1) && tty.isatty(2);

/**
 * Expose `Base`.
 */

exports = module.exports = Base;

/**
 * Enable coloring by default.
 */

exports.useColors = isatty;

/**
 * Default color map.
 */

exports.colors = {
    'pass': 90
  , 'fail': 31
  , 'bright pass': 92
  , 'bright fail': 91
  , 'bright yellow': 93
  , 'pending': 36
  , 'suite': 0
  , 'error title': 0
  , 'error message': 31
  , 'error stack': 90
  , 'checkmark': 32
  , 'fast': 90
  , 'medium': 33
  , 'slow': 31
  , 'green': 32
  , 'light': 90
  , 'diff gutter': 90
  , 'diff added': 42
  , 'diff removed': 41
};

/**
 * Default symbol map.
 */

exports.symbols = {
  ok: '✓',
  err: '✖',
  dot: '․'
};

// With node.js on Windows: use symbols available in terminal default fonts
if ('win32' == process.platform) {
  exports.symbols.ok = '\u221A';
  exports.symbols.err = '\u00D7';
  exports.symbols.dot = '.';
}

/**
 * Color `str` with the given `type`,
 * allowing colors to be disabled,
 * as well as user-defined color
 * schemes.
 *
 * @param {String} type
 * @param {String} str
 * @return {String}
 * @api private
 */

var color = exports.color = function(type, str) {
  if (!exports.useColors) return str;
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
};

/**
 * Expose term window size, with some
 * defaults for when stderr is not a tty.
 */

exports.window = {
  width: isatty
    ? process.stdout.getWindowSize
      ? process.stdout.getWindowSize(1)[0]
      : tty.getWindowSize()[1]
    : 75
};

/**
 * Expose some basic cursor interactions
 * that are common among reporters.
 */

exports.cursor = {
  hide: function(){
    process.stdout.write('\u001b[?25l');
  },

  show: function(){
    process.stdout.write('\u001b[?25h');
  },

  deleteLine: function(){
    process.stdout.write('\u001b[2K');
  },

  beginningOfLine: function(){
    process.stdout.write('\u001b[0G');
  },

  CR: function(){
    exports.cursor.deleteLine();
    exports.cursor.beginningOfLine();
  }
};

/**
 * Outut the given `failures` as a list.
 *
 * @param {Array} failures
 * @api public
 */

exports.list = function(failures){
  console.error();
  failures.forEach(function(test, i){
    // format
    var fmt = color('error title', '  %s) %s:\n')
      + color('error message', '     %s')
      + color('error stack', '\n%s\n');

    // msg
    var err = test.err
      , message = err.message || ''
      , stack = err.stack || message
      , index = stack.indexOf(message) + message.length
      , msg = stack.slice(0, index)
      , actual = err.actual
      , expected = err.expected
      , escape = true;

    // explicitly show diff
    if (err.showDiff) {
      escape = false;
      err.actual = actual = JSON.stringify(actual, null, 2);
      err.expected = expected = JSON.stringify(expected, null, 2);
    }

    // actual / expected diff
    if ('string' == typeof actual && 'string' == typeof expected) {
      var len = Math.max(actual.length, expected.length);

      if (len < 20) msg = errorDiff(err, 'Chars', escape);
      else msg = errorDiff(err, 'Words', escape);

      // linenos
      var lines = msg.split('\n');
      if (lines.length > 4) {
        var width = String(lines.length).length;
        msg = lines.map(function(str, i){
          return pad(++i, width) + ' |' + ' ' + str;
        }).join('\n');
      }

      // legend
      msg = '\n'
        + color('diff removed', 'actual')
        + ' '
        + color('diff added', 'expected')
        + '\n\n'
        + msg
        + '\n';

      // indent
      msg = msg.replace(/^/gm, '      ');

      fmt = color('error title', '  %s) %s:\n%s')
        + color('error stack', '\n%s\n');
    }

    // indent stack trace without msg
    stack = stack.slice(index ? index + 1 : index)
      .replace(/^/gm, '  ');

    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
  });
};

/**
 * Initialize a new `Base` reporter.
 *
 * All other reporters generally
 * inherit from this reporter, providing
 * stats such as test duration, number
 * of tests passed / failed etc.
 *
 * @param {Runner} runner
 * @api public
 */

function Base(runner) {
  var self = this
    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
    , failures = this.failures = [];

  if (!runner) return;
  this.runner = runner;

  runner.stats = stats;

  runner.on('start', function(){
    stats.start = new Date;
  });

  runner.on('suite', function(suite){
    stats.suites = stats.suites || 0;
    suite.root || stats.suites++;
  });

  runner.on('test end', function(test){
    stats.tests = stats.tests || 0;
    stats.tests++;
  });

  runner.on('pass', function(test){
    stats.passes = stats.passes || 0;

    var medium = test.slow() / 2;
    test.speed = test.duration > test.slow()
      ? 'slow'
      : test.duration > medium
        ? 'medium'
        : 'fast';

    stats.passes++;
  });

  runner.on('fail', function(test, err){
    stats.failures = stats.failures || 0;
    stats.failures++;
    test.err = err;
    failures.push(test);
  });

  runner.on('end', function(){
    stats.end = new Date;
    stats.duration = new Date - stats.start;
  });

  runner.on('pending', function(){
    stats.pending++;
  });
}

/**
 * Output common epilogue used by many of
 * the bundled reporters.
 *
 * @api public
 */

Base.prototype.epilogue = function(){
  var stats = this.stats
    , fmt
    , tests;

  console.log();

  function pluralize(n) {
    return 1 == n ? 'test' : 'tests';
  }

  // failure
  if (stats.failures) {
    fmt = color('bright fail', '  ' + exports.symbols.err)
      + color('fail', ' %d of %d %s failed')
      + color('light', ':')

    console.error(fmt,
      stats.failures,
      this.runner.total,
      pluralize(this.runner.total));

    Base.list(this.failures);
    console.error();
    return;
  }

  // pass
  fmt = color('bright pass', '  ' + exports.symbols.ok)
    + color('green', ' %d %s complete')
    + color('light', ' (%s)');

  console.log(fmt,
    stats.tests || 0,
    pluralize(stats.tests),
    ms(stats.duration));

  // pending
  if (stats.pending) {
    fmt = color('pending', '  •')
      + color('pending', ' %d %s pending');

    console.log(fmt, stats.pending, pluralize(stats.pending));
  }

  console.log();
};

/**
 * Pad the given `str` to `len`.
 *
 * @param {String} str
 * @param {String} len
 * @return {String}
 * @api private
 */

function pad(str, len) {
  str = String(str);
  return Array(len - str.length + 1).join(' ') + str;
}

/**
 * Return a character diff for `err`.
 *
 * @param {Error} err
 * @return {String}
 * @api private
 */

function errorDiff(err, type, escape) {
  return diff['diff' + type](err.actual, err.expected).map(function(str){
    if (escape) {
      str.value = str.value
        .replace(/\t/g, '<tab>')
        .replace(/\r/g, '<CR>')
        .replace(/\n/g, '<LF>\n');
    }
    if (str.added) return colorLines('diff added', str.value);
    if (str.removed) return colorLines('diff removed', str.value);
    return str.value;
  }).join('');
}

/**
 * Color lines for `str`, using the color `name`.
 *
 * @param {String} name
 * @param {String} str
 * @return {String}
 * @api private
 */

function colorLines(name, str) {
  return str.split('\n').map(function(str){
    return color(name, str);
  }).join('\n');
}
<commit_msg>remove trailing unicode chars in Base output<commit_after>
/**
 * Module dependencies.
 */

var tty = require('tty')
  , diff = require('diff')
  , ms = require('../ms');

/**
 * Save timer references to avoid Sinon interfering (see GH-237).
 */

var Date = global.Date
  , setTimeout = global.setTimeout
  , setInterval = global.setInterval
  , clearTimeout = global.clearTimeout
  , clearInterval = global.clearInterval;

/**
 * Check if both stdio streams are associated with a tty.
 */

var isatty = tty.isatty(1) && tty.isatty(2);

/**
 * Expose `Base`.
 */

exports = module.exports = Base;

/**
 * Enable coloring by default.
 */

exports.useColors = isatty;

/**
 * Default color map.
 */

exports.colors = {
    'pass': 90
  , 'fail': 31
  , 'bright pass': 92
  , 'bright fail': 91
  , 'bright yellow': 93
  , 'pending': 36
  , 'suite': 0
  , 'error title': 0
  , 'error message': 31
  , 'error stack': 90
  , 'checkmark': 32
  , 'fast': 90
  , 'medium': 33
  , 'slow': 31
  , 'green': 32
  , 'light': 90
  , 'diff gutter': 90
  , 'diff added': 42
  , 'diff removed': 41
};

/**
 * Default symbol map.
 */

exports.symbols = {
  ok: '✓',
  err: '✖',
  dot: '․'
};

// With node.js on Windows: use symbols available in terminal default fonts
if ('win32' == process.platform) {
  exports.symbols.ok = '\u221A';
  exports.symbols.err = '\u00D7';
  exports.symbols.dot = '.';
}

/**
 * Color `str` with the given `type`,
 * allowing colors to be disabled,
 * as well as user-defined color
 * schemes.
 *
 * @param {String} type
 * @param {String} str
 * @return {String}
 * @api private
 */

var color = exports.color = function(type, str) {
  if (!exports.useColors) return str;
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
};

/**
 * Expose term window size, with some
 * defaults for when stderr is not a tty.
 */

exports.window = {
  width: isatty
    ? process.stdout.getWindowSize
      ? process.stdout.getWindowSize(1)[0]
      : tty.getWindowSize()[1]
    : 75
};

/**
 * Expose some basic cursor interactions
 * that are common among reporters.
 */

exports.cursor = {
  hide: function(){
    process.stdout.write('\u001b[?25l');
  },

  show: function(){
    process.stdout.write('\u001b[?25h');
  },

  deleteLine: function(){
    process.stdout.write('\u001b[2K');
  },

  beginningOfLine: function(){
    process.stdout.write('\u001b[0G');
  },

  CR: function(){
    exports.cursor.deleteLine();
    exports.cursor.beginningOfLine();
  }
};

/**
 * Outut the given `failures` as a list.
 *
 * @param {Array} failures
 * @api public
 */

exports.list = function(failures){
  console.error();
  failures.forEach(function(test, i){
    // format
    var fmt = color('error title', '  %s) %s:\n')
      + color('error message', '     %s')
      + color('error stack', '\n%s\n');

    // msg
    var err = test.err
      , message = err.message || ''
      , stack = err.stack || message
      , index = stack.indexOf(message) + message.length
      , msg = stack.slice(0, index)
      , actual = err.actual
      , expected = err.expected
      , escape = true;

    // explicitly show diff
    if (err.showDiff) {
      escape = false;
      err.actual = actual = JSON.stringify(actual, null, 2);
      err.expected = expected = JSON.stringify(expected, null, 2);
    }

    // actual / expected diff
    if ('string' == typeof actual && 'string' == typeof expected) {
      var len = Math.max(actual.length, expected.length);

      if (len < 20) msg = errorDiff(err, 'Chars', escape);
      else msg = errorDiff(err, 'Words', escape);

      // linenos
      var lines = msg.split('\n');
      if (lines.length > 4) {
        var width = String(lines.length).length;
        msg = lines.map(function(str, i){
          return pad(++i, width) + ' |' + ' ' + str;
        }).join('\n');
      }

      // legend
      msg = '\n'
        + color('diff removed', 'actual')
        + ' '
        + color('diff added', 'expected')
        + '\n\n'
        + msg
        + '\n';

      // indent
      msg = msg.replace(/^/gm, '      ');

      fmt = color('error title', '  %s) %s:\n%s')
        + color('error stack', '\n%s\n');
    }

    // indent stack trace without msg
    stack = stack.slice(index ? index + 1 : index)
      .replace(/^/gm, '  ');

    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
  });
};

/**
 * Initialize a new `Base` reporter.
 *
 * All other reporters generally
 * inherit from this reporter, providing
 * stats such as test duration, number
 * of tests passed / failed etc.
 *
 * @param {Runner} runner
 * @api public
 */

function Base(runner) {
  var self = this
    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
    , failures = this.failures = [];

  if (!runner) return;
  this.runner = runner;

  runner.stats = stats;

  runner.on('start', function(){
    stats.start = new Date;
  });

  runner.on('suite', function(suite){
    stats.suites = stats.suites || 0;
    suite.root || stats.suites++;
  });

  runner.on('test end', function(test){
    stats.tests = stats.tests || 0;
    stats.tests++;
  });

  runner.on('pass', function(test){
    stats.passes = stats.passes || 0;

    var medium = test.slow() / 2;
    test.speed = test.duration > test.slow()
      ? 'slow'
      : test.duration > medium
        ? 'medium'
        : 'fast';

    stats.passes++;
  });

  runner.on('fail', function(test, err){
    stats.failures = stats.failures || 0;
    stats.failures++;
    test.err = err;
    failures.push(test);
  });

  runner.on('end', function(){
    stats.end = new Date;
    stats.duration = new Date - stats.start;
  });

  runner.on('pending', function(){
    stats.pending++;
  });
}

/**
 * Output common epilogue used by many of
 * the bundled reporters.
 *
 * @api public
 */

Base.prototype.epilogue = function(){
  var stats = this.stats
    , fmt
    , tests;

  console.log();

  function pluralize(n) {
    return 1 == n ? 'test' : 'tests';
  }

  // failure
  if (stats.failures) {
    fmt = color('bright fail', '  ' + exports.symbols.err)
      + color('fail', ' %d of %d %s failed')
      + color('light', ':')

    console.error(fmt,
      stats.failures,
      this.runner.total,
      pluralize(this.runner.total));

    Base.list(this.failures);
    console.error();
    return;
  }

  // pass
  fmt = color('bright pass', ' ')
    + color('green', ' %d %s complete')
    + color('light', ' (%s)');

  console.log(fmt,
    stats.tests || 0,
    pluralize(stats.tests),
    ms(stats.duration));

  // pending
  if (stats.pending) {
    fmt = color('pending', ' ')
      + color('pending', ' %d %s pending');

    console.log(fmt, stats.pending, pluralize(stats.pending));
  }

  console.log();
};

/**
 * Pad the given `str` to `len`.
 *
 * @param {String} str
 * @param {String} len
 * @return {String}
 * @api private
 */

function pad(str, len) {
  str = String(str);
  return Array(len - str.length + 1).join(' ') + str;
}

/**
 * Return a character diff for `err`.
 *
 * @param {Error} err
 * @return {String}
 * @api private
 */

function errorDiff(err, type, escape) {
  return diff['diff' + type](err.actual, err.expected).map(function(str){
    if (escape) {
      str.value = str.value
        .replace(/\t/g, '<tab>')
        .replace(/\r/g, '<CR>')
        .replace(/\n/g, '<LF>\n');
    }
    if (str.added) return colorLines('diff added', str.value);
    if (str.removed) return colorLines('diff removed', str.value);
    return str.value;
  }).join('');
}

/**
 * Color lines for `str`, using the color `name`.
 *
 * @param {String} name
 * @param {String} str
 * @return {String}
 * @api private
 */

function colorLines(name, str) {
  return str.split('\n').map(function(str){
    return color(name, str);
  }).join('\n');
}
<|endoftext|>