<commit_before>'use strict';

const logPayload = require('./util/logging-util').formattedPayload;

/**
 * @param  {Object} message_queue      message_queue
 * @param  {Object} message_processing message_processing
 * @param  {Bunyan} logger             logger
 * @return {Object}                    methods
 */
exports.create = function(message_queue, message_processing, logger) {
  return {
    receiveMessageBatch: receiveMessageBatch,
  };

  /**
   * Recursive call to receive and process messages infinitely.
   * @type {Function}
   * @param {String} queue_name Name of queue to capture messages from.
   * @param {Function} callback Invoked with [err].
   */
  function receiveMessageBatch(queue_name, callback) {
    message_queue.receiveQueueMessages(queue_name, (err, sqs_messages) => {
      let message_count;

      if (err) {
        err.payload = {
          queue_name: queue_name,
        };
        logger.warn(err, 'Error receiving messages for queue %s', queue_name);
        callback(err);
        return;
      }

      message_count = sqs_messages.length;

      logger.info(logPayload({
        queue: queue_name,
        count: message_count,
      }), 'Message batch received');

      // Receive next batch immediately
      if (!message_count) {
        callback();
        return;
      }

      message_processing.processMessages(sqs_messages, queue_name, () => {
        logger.info(logPayload({
          queue: queue_name,
          count: message_count,
        }), 'Done processing message batch');
        callback();
      });
    });
  }
};
<commit_msg>fix: Not logging empty message batches<commit_after>'use strict';

const logPayload = require('./util/logging-util').formattedPayload;

/**
 * @param  {Object} message_queue      message_queue
 * @param  {Object} message_processing message_processing
 * @param  {Bunyan} logger             logger
 * @return {Object}                    methods
 */
exports.create = function(message_queue, message_processing, logger) {
  return {
    receiveMessageBatch: receiveMessageBatch,
  };

  /**
   * Recursive call to receive and process messages infinitely.
   * @type {Function}
   * @param {String} queue_name Name of queue to capture messages from.
   * @param {Function} callback Invoked with [err].
   */
  function receiveMessageBatch(queue_name, callback) {
    message_queue.receiveQueueMessages(queue_name, (err, sqs_messages) => {
      if (err) {
        err.payload = {
          queue: queue_name,
        };
        logger.warn(err, 'Error receiving messages for SQS queue');
        callback(err);
        return;
      }

      const message_count = sqs_messages.length;

      // Receive next batch immediately
      if (!message_count) {
        callback();
        return;
      }

      logger.info(logPayload({
        queue: queue_name,
        count: message_count,
      }), 'Message batch received');

      message_processing.processMessages(sqs_messages, queue_name, () => {
        logger.info(logPayload({
          queue: queue_name,
          count: message_count,
        }), 'Done processing message batch');
        callback();
      });
    });
  }
};
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var SessionStore = require('../stores/session');

/**
 * Load state.
 *
 * This middleware is used to load state associated with a request.  The state
 * will be made available at `req.state`.
 *
 * HTTP is a stateless protocol.  In order to support stateful interactions, the
 * client and server need to operate in coordination.  The server is responsible
 * for persisting state associated with a request.  The client is responsible for
 * indicating that state in subsequent requests to the server (via a `state`
 * parameter in the query or body, by default).  The server then loads the
 * previously persisted state in order to continue processing the transaction.
 *
 * Options:
 *
 *     name   set req.state only if the state name is equal to the option value
 *
 * @return {Function}
 * @api public
 */
module.exports = function(store, options) {
  if (typeof options == 'string') {
    options = { name: options };
  }
  options = options || {};

  var name = options.name;
  var getHandle = options.getHandle || function(req) {
    return (req.query && req.query.state) || (req.body && req.body.state);
  }

  return function loadState(req, res, next) {
    var h = getHandle(req);
    if (!h) {
      if (options.required) {
        return next(new Error("Failed to load required state '" + name + "'"));
      }
      return next();
    }

    store.load(req, h, function (err, state) {
      if (err) { return next(err); }
      if (!name) {
        req.state = state;
      } else if (state && name == state.name) {
        req.state = state;
      } else {
        // The loaded state is not the expected state.  Save what was loaded,
        // as an optimization to avoid re-loading later if the state is resumed.
        req._state = state;
      }

      if (options.required && !req.state) {
        return next(new Error("Failed to load required state '" + name + "'"));
      }
      next();
    });
  };
};
<commit_msg>Remove unused require statement.<commit_after>/**
 * Load state.
 *
 * This middleware is used to load state associated with a request.  The state
 * will be made available at `req.state`.
 *
 * HTTP is a stateless protocol.  In order to support stateful interactions, the
 * client and server need to operate in coordination.  The server is responsible
 * for persisting state associated with a request.  The client is responsible for
 * indicating that state in subsequent requests to the server (via a `state`
 * parameter in the query or body, by default).  The server then loads the
 * previously persisted state in order to continue processing the transaction.
 *
 * Options:
 *
 *     name   set req.state only if the state name is equal to the option value
 *
 * @return {Function}
 * @api public
 */
module.exports = function(store, options) {
  if (typeof options == 'string') {
    options = { name: options };
  }
  options = options || {};

  var name = options.name;
  var getHandle = options.getHandle || function(req) {
    return (req.query && req.query.state) || (req.body && req.body.state);
  }

  return function loadState(req, res, next) {
    var h = getHandle(req);
    if (!h) {
      if (options.required) {
        return next(new Error("Failed to load required state '" + name + "'"));
      }
      return next();
    }

    store.load(req, h, function (err, state) {
      if (err) { return next(err); }
      if (!name) {
        req.state = state;
      } else if (state && name == state.name) {
        req.state = state;
      } else {
        // The loaded state is not the expected state.  Save what was loaded,
        // as an optimization to avoid re-loading later if the state is resumed.
        req._state = state;
      }

      if (options.required && !req.state) {
        return next(new Error("Failed to load required state '" + name + "'"));
      }
      next();
    });
  };
};
<|endoftext|>


<commit_before>// Generated by CoffeeScript 1.10.0
(function() {
  'use strict';
  var BaseDAO, BaseField, BaseModel, ForeignKey, Joi, ManyToMany, ManyToOne, Promise, _, fs, knex, knexConf, moduleKeywords,
    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  Joi = require('joi');

  _ = require('underscore');

  fs = require('fs');

  knexConf = require(process.cwd() + '/knexfile');

  knex = require('knex')(knexConf[process.env.NODE_ENV]);

  Promise = require('bluebird');

  ForeignKey = require('../fields/foreignKey');

  BaseField = require('../fields/baseField');

  ManyToMany = require('../fields/manyToMany');

  ManyToOne = require('../fields/manyToOne');

  BaseDAO = require('./../dao/baseDao');

  moduleKeywords = ['extended', 'included'];

  BaseModel = (function() {
    BaseModel.extend = function(obj) {
      var key, ref, value;
      this.metadata = {};
      for (key in obj) {
        value = obj[key];
        if (indexOf.call(moduleKeywords, key) < 0) {
          this.metadata[key] = value;
        }
      }
      if (this.metadata.model == null) {
        this.metadata.model = this.name;
      }
      if (this.metadata.singular == null) {
        this.metadata.singular = this._camelToSnakeCase(this.name);
      }
      if (this.metadata.tableName == null) {
        this.metadata.tableName = this._camelToSnakeCase(this.name) + 's';
      }
      if (this.metadata.primaryKey == null) {
        this.metadata.primaryKey = 'id';
      }
      if (this.metadata.timestamps == null) {
        this.metadata.timestamps = true;
      }
      if ((ref = obj.extended) != null) {
        ref.apply(this);
      }
      return this;
    };

    BaseModel.include = function(obj) {
      var key, ref, value;
      this.prototype['attributes'] = {};
      for (key in obj) {
        value = obj[key];
        if (indexOf.call(moduleKeywords, key) < 0) {
          this.prototype['attributes'][key] = value;
        }
      }
      _.extend(this.prototype['attributes'], this.prototype.timestampAttributes);
      if ((ref = obj.included) != null) {
        ref.apply(this);
      }
      return this;
    };

    BaseModel.prototype.timestampAttributes = {
      createdAt: new BaseField({
        schema: Joi.date().format('YYYY-MM-DD HH:mm:ss'),
        name: 'createdAt'
      }),
      whoCreated: new BaseField({
        schema: Joi.number().integer().positive(),
        name: 'whoCreated',
        dbField: 'who_created_id'
      }),
      deletedAt: new BaseField({
        schema: Joi.date().format('YYYY-MM-DD HH:mm:ss'),
        name: 'deletedAt'
      }),
      whoDeleted: new BaseField({
        schema: Joi.number().integer().positive(),
        name: 'whoDeleted',
        dbField: 'who_deleted_id'
      }),
      isDeleted: new BaseField({
        schema: Joi.boolean(),
        name: 'isDeleted'
      })
    };

    BaseModel.objects = function() {
      var dao, daoFileName, modules, modulesDir, self;
      modulesDir = process.cwd() + '/api/';
      self = this;
      dao = void 0;
      daoFileName = self.metadata.model.substring(0, 1).toLowerCase() + self.metadata.model.substring(1);
      modules = fs.readdirSync(modulesDir);
      _.each(modules, function(moduleName) {
        var currentModule, insideModule, ref;
        if (!moduleName.startsWith('.')) {
          insideModule = fs.readdirSync(modulesDir + moduleName);
          if (indexOf.call(insideModule, 'dao') >= 0) {
            currentModule = fs.readdirSync(modulesDir + moduleName + '/dao');
            if (ref = daoFileName + '.coffee', indexOf.call(currentModule, ref) >= 0) {
              return dao = require(modulesDir + moduleName + '/dao/' + daoFileName);
            }
          }
        }
      });
      if (dao != null) {
        return new dao(this);
      } else {
        return new BaseDAO(this);
      }
    };

    BaseModel._snakeToCamelCase = function(string, attributes) {
      var camelCase;
      camelCase = string.replace(/(_\w)/g, function(m) {
        return m[1].toUpperCase();
      });
      if (attributes != null) {
        if (attributes[camelCase] instanceof ForeignKey) {
          camelCase.slice(0, -2);
        }
      }
      return camelCase;
    };

    BaseModel._camelToSnakeCase = function(string, attributes) {
      var snakeCase;
      snakeCase = (string.replace(/\.?([A-Z])/g, function(m, n) {
        return '_' + n.toLowerCase();
      })).replace(/^_/, '');
      if (attributes != null) {
        if (attributes[string] instanceof ForeignKey) {
          snakeCase += '_id';
        }
      }
      return snakeCase;
    };

    BaseModel.getSchema = function(fields, partial) {
      var attributesWithSchema;
      if (fields == null) {
        fields = _.keys(this.prototype.attributes);
      }
      attributesWithSchema = _.pick(this.prototype.attributes, function(val, key) {
        return (val.attributes.schema != null) && !(key in BaseModel.prototype.timestampAttributes) && indexOf.call(fields, key) >= 0;
      });
      return _.mapObject(attributesWithSchema, function(val, key) {
        var schema;
        schema = val.attributes.schema;
        if (val.attributes.required && !partial) {
          schema = schema.required();
        }
        return schema;
      });
    };

    function BaseModel(properties) {
      this["delete"] = bind(this["delete"], this);
      this.save = bind(this.save, this);
      this.validate = bind(this.validate, this);
      this.toJSON = bind(this.toJSON, this);
      this.set = bind(this.set, this);
      this.get = bind(this.get, this);
      this._toDatabaseFields = bind(this._toDatabaseFields, this);
      var error, error1, manyToManyManager, manyToOneManager;
      manyToOneManager = ManyToOne.getManyToOneManager();
      manyToManyManager = ManyToMany.getManyToManyManager();
      _.each(this.attributes, (function(_this) {
        return function(val, key) {
          var throughFields, toModel;
          if (!_.has(val.attributes, 'dbField')) {
            val.attributes.dbField = _this.constructor._camelToSnakeCase(key, _this.attributes);
          }
          if (!_.has(val.attributes, 'name')) {
            val.attributes.name = key;
          }
          if (val instanceof ManyToMany) {
            if (!_.has(val.attributes, 'throughFields')) {
              toModel = require(val.attributes.toModel);
              throughFields = [];
              throughFields.push(_this.constructor.metadata.singular + '_' + _this.constructor.metadata.primaryKey);
              throughFields.push(toModel.metadata.singular + '_' + toModel.metadata.primaryKey);
              val.attributes.throughFields = throughFields;
            }
            _this[key] = new manyToManyManager(_this, key, val);
          }
          if (val instanceof ManyToOne) {
            if (!_.has(val.attributes, 'referenceField')) {
              val.attributes.referenceField = _this.constructor.metadata.singular + '_' + _this.constructor.metadata.primaryKey;
            }
            _this[key] = new manyToOneManager(_this, key, val);
          }
          return val.attributes.modelMeta = _this.constructor.metadata;
        };
      })(this));
      try {
        this.set(properties);
      } catch (error1) {
        error = error1;
        throw error;
      }
    }

    BaseModel.prototype._toDatabaseFields = function() {
      var databaseObject, key, ref, value;
      databaseObject = {};
      ref = this.attributes;
      for (key in ref) {
        value = ref[key];
        if (this[key] !== void 0 && value.attributes.dbField && !value.attributes.abstract) {
          databaseObject[value.attributes.dbField] = value.attributes.set != null ? value.attributes.set(this) : this[key];
        }
      }
      return databaseObject;
    };

    BaseModel.prototype.get = function(key, toObject) {
      var lookup;
      if (key in this.attributes) {
        if (this.attributes[key].attributes.get != null) {
          return this.attributes[key].attributes.get(this);
        } else {
          if (this.attributes[key] instanceof ForeignKey && (this[key] != null)) {
            lookup = {};
            lookup[this.attributes[key].attributes.referenceField] = this[key];
            return this.attributes[key].attributes.referenceModel.objects().get({
              lookup: lookup,
              toObject: toObject
            }).then(function(result) {
              return result;
            })["catch"](function(error) {
              throw error;
            });
          } else {
            return this[key];
          }
        }
      } else {
        throw new TypeError("The '" + key + "' field does not match any attribute of model " + this.constructor.metadata.model + "!");
      }
    };

    BaseModel.prototype.set = function(properties) {
      return _.each(properties, (function(_this) {
        return function(value, key) {
          if (key in _this.attributes) {
            return _this[key] = value;
          } else {
            throw new TypeError("The '" + key + "' field does not match any attribute of model " + _this.constructor.metadata.model + "!");
          }
        };
      })(this));
    };

    BaseModel.prototype.toJSON = function(arg) {
      var attributes, jsonObject;
      attributes = (arg != null ? arg : {}).attributes;
      if (attributes == null) {
        attributes = _.keys(this.attributes);
      }
      jsonObject = {};
      _.each(attributes, (function(_this) {
        return function(key, val) {
          if (!(_this.attributes[key] instanceof ManyToMany) && !(_this.attributes[key] instanceof ManyToOne)) {
            if (_this.attributes[key] instanceof ForeignKey) {
              return jsonObject[key] = _this[key];
            } else {
              return jsonObject[key] = _this.get(key) !== void 0 ? _this.get(key) : void 0;
            }
          }
        };
      })(this));
      return jsonObject;
    };

    BaseModel.prototype.validate = function(arg) {
      var promises, trx;
      trx = (arg != null ? arg : {}).trx;
      promises = [];
      _.each(this.attributes, (function(_this) {
        return function(value, key) {
          if (value.attributes.abstract == null) {
            return promises.push(value.validate(_this, {
              primaryKey: _this[_this.constructor.metadata.primaryKey],
              trx: trx
            }));
          }
        };
      })(this));
      return Promise.all(promises).then(function(values) {
        var validationResultObject;
        validationResultObject = {};
        _.each(_.compact(values), function(val, key) {
          return _.extend(validationResultObject, val);
        });
        return validationResultObject;
      });
    };

    BaseModel.prototype.save = function(arg) {
      var ref, returning, toObject;
      ref = arg != null ? arg : {}, returning = ref.returning, toObject = ref.toObject;
      return this.validate().then((function(_this) {
        return function(validationResult) {
          if (!(_.isEmpty(validationResult))) {
            throw validationResult;
          }
          if (_this[_this.constructor.metadata.primaryKey] != null) {
            return _this.constructor.objects().update({
              obj: _this,
              returning: returning,
              toObject: toObject
            }).then(function(res) {
              return res;
            });
          } else {
            return _this.constructor.objects().create({
              payload: _this._toDatabaseFields(),
              returning: returning,
              toObject: toObject
            }).then(function(res) {
              return res;
            });
          }
        };
      })(this))["catch"](function(error) {
        throw error;
      });
    };

    BaseModel.prototype["delete"] = function(whoDeleted) {
      var primaryKey;
      primaryKey = this.constructor.metadata.primaryKey;
      if (this[primaryKey] != null) {
        return this.constructor.objects()["delete"](this[primaryKey], whoDeleted).then(function(result) {
          return result;
        })["catch"](function(error) {
          throw error;
        });
      } else {
        throw new Error("This " + this.constructor.metadata.model + " does not have primary key set!");
      }
    };

    return BaseModel;

  })();

  module.exports = BaseModel;

}).call(this);
<commit_msg>Acceptable attributes in Model's metadata.<commit_after>// Generated by CoffeeScript 1.10.0
(function() {
  'use strict';
  var BaseDAO, BaseField, BaseModel, ForeignKey, Joi, ManyToMany, ManyToOne, Promise, _, acceptableMetadataAttributes, fs, knex, knexConf, moduleKeywords,
    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
    indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  Joi = require('joi');

  _ = require('underscore');

  fs = require('fs');

  knexConf = require(process.cwd() + '/knexfile');

  knex = require('knex')(knexConf[process.env.NODE_ENV]);

  Promise = require('bluebird');

  ForeignKey = require('../fields/foreignKey');

  BaseField = require('../fields/baseField');

  ManyToMany = require('../fields/manyToMany');

  ManyToOne = require('../fields/manyToOne');

  BaseDAO = require('./../dao/baseDao');

  moduleKeywords = ['extended', 'included'];

  acceptableMetadataAttributes = ['model', 'singular', 'tableName', 'primaryKey', 'timestamps'];

  BaseModel = (function() {
    BaseModel.extend = function(obj) {
      var key, ref, value;
      this.metadata = {};
      for (key in obj) {
        value = obj[key];
        if (!(indexOf.call(moduleKeywords, key) < 0)) {
          continue;
        }
        if (indexOf.call(acceptableMetadataAttributes, key) < 0) {
          throw new Error("The '" + key + "' attribute in Model's metadata is not acceptable.\n Acceptable attributes are " + acceptableMetadataAttributes + ".");
        }
        this.metadata[key] = value;
      }
      if (this.metadata.model == null) {
        this.metadata.model = this.name;
      }
      if (this.metadata.singular == null) {
        this.metadata.singular = this._camelToSnakeCase(this.name);
      }
      if (this.metadata.tableName == null) {
        this.metadata.tableName = this._camelToSnakeCase(this.name) + 's';
      }
      if (this.metadata.primaryKey == null) {
        this.metadata.primaryKey = 'id';
      }
      if (this.metadata.timestamps == null) {
        this.metadata.timestamps = true;
      }
      if ((ref = obj.extended) != null) {
        ref.apply(this);
      }
      return this;
    };

    BaseModel.include = function(obj) {
      var key, ref, value;
      this.prototype['attributes'] = {};
      for (key in obj) {
        value = obj[key];
        if (indexOf.call(moduleKeywords, key) < 0) {
          this.prototype['attributes'][key] = value;
        }
      }
      _.extend(this.prototype['attributes'], this.prototype.timestampAttributes);
      if ((ref = obj.included) != null) {
        ref.apply(this);
      }
      return this;
    };

    BaseModel.prototype.timestampAttributes = {
      createdAt: new BaseField({
        schema: Joi.date().format('YYYY-MM-DD HH:mm:ss'),
        name: 'createdAt'
      }),
      whoCreated: new BaseField({
        schema: Joi.number().integer().positive(),
        name: 'whoCreated',
        dbField: 'who_created_id'
      }),
      deletedAt: new BaseField({
        schema: Joi.date().format('YYYY-MM-DD HH:mm:ss'),
        name: 'deletedAt'
      }),
      whoDeleted: new BaseField({
        schema: Joi.number().integer().positive(),
        name: 'whoDeleted',
        dbField: 'who_deleted_id'
      }),
      isDeleted: new BaseField({
        schema: Joi.boolean(),
        name: 'isDeleted'
      })
    };

    BaseModel.objects = function() {
      var dao, daoFileName, modules, modulesDir, self;
      modulesDir = process.cwd() + '/api/';
      self = this;
      dao = void 0;
      daoFileName = self.metadata.model.substring(0, 1).toLowerCase() + self.metadata.model.substring(1);
      modules = fs.readdirSync(modulesDir);
      _.each(modules, function(moduleName) {
        var currentModule, insideModule, ref;
        if (!moduleName.startsWith('.')) {
          insideModule = fs.readdirSync(modulesDir + moduleName);
          if (indexOf.call(insideModule, 'dao') >= 0) {
            currentModule = fs.readdirSync(modulesDir + moduleName + '/dao');
            if (ref = daoFileName + '.coffee', indexOf.call(currentModule, ref) >= 0) {
              return dao = require(modulesDir + moduleName + '/dao/' + daoFileName);
            }
          }
        }
      });
      if (dao != null) {
        return new dao(this);
      } else {
        return new BaseDAO(this);
      }
    };

    BaseModel._snakeToCamelCase = function(string, attributes) {
      var camelCase;
      camelCase = string.replace(/(_\w)/g, function(m) {
        return m[1].toUpperCase();
      });
      if (attributes != null) {
        if (attributes[camelCase] instanceof ForeignKey) {
          camelCase.slice(0, -2);
        }
      }
      return camelCase;
    };

    BaseModel._camelToSnakeCase = function(string, attributes) {
      var snakeCase;
      snakeCase = (string.replace(/\.?([A-Z])/g, function(m, n) {
        return '_' + n.toLowerCase();
      })).replace(/^_/, '');
      if (attributes != null) {
        if (attributes[string] instanceof ForeignKey) {
          snakeCase += '_id';
        }
      }
      return snakeCase;
    };

    BaseModel.getSchema = function(fields, partial) {
      var attributesWithSchema;
      if (fields == null) {
        fields = _.keys(this.prototype.attributes);
      }
      attributesWithSchema = _.pick(this.prototype.attributes, function(val, key) {
        return (val.attributes.schema != null) && !(key in BaseModel.prototype.timestampAttributes) && indexOf.call(fields, key) >= 0;
      });
      return _.mapObject(attributesWithSchema, function(val, key) {
        var schema;
        schema = val.attributes.schema;
        if (val.attributes.required && !partial) {
          schema = schema.required();
        }
        return schema;
      });
    };

    function BaseModel(properties) {
      this["delete"] = bind(this["delete"], this);
      this.save = bind(this.save, this);
      this.validate = bind(this.validate, this);
      this.toJSON = bind(this.toJSON, this);
      this.set = bind(this.set, this);
      this.get = bind(this.get, this);
      this._toDatabaseFields = bind(this._toDatabaseFields, this);
      var error, error1, manyToManyManager, manyToOneManager;
      manyToOneManager = ManyToOne.getManyToOneManager();
      manyToManyManager = ManyToMany.getManyToManyManager();
      _.each(this.attributes, (function(_this) {
        return function(val, key) {
          var throughFields, toModel;
          if (!_.has(val.attributes, 'dbField')) {
            val.attributes.dbField = _this.constructor._camelToSnakeCase(key, _this.attributes);
          }
          if (!_.has(val.attributes, 'name')) {
            val.attributes.name = key;
          }
          if (val instanceof ManyToMany) {
            if (!_.has(val.attributes, 'throughFields')) {
              toModel = require(val.attributes.toModel);
              throughFields = [];
              throughFields.push(_this.constructor.metadata.singular + '_' + _this.constructor.metadata.primaryKey);
              throughFields.push(toModel.metadata.singular + '_' + toModel.metadata.primaryKey);
              val.attributes.throughFields = throughFields;
            }
            _this[key] = new manyToManyManager(_this, key, val);
          }
          if (val instanceof ManyToOne) {
            if (!_.has(val.attributes, 'referenceField')) {
              val.attributes.referenceField = _this.constructor.metadata.singular + '_' + _this.constructor.metadata.primaryKey;
            }
            _this[key] = new manyToOneManager(_this, key, val);
          }
          return val.attributes.modelMeta = _this.constructor.metadata;
        };
      })(this));
      try {
        this.set(properties);
      } catch (error1) {
        error = error1;
        throw error;
      }
    }

    BaseModel.prototype._toDatabaseFields = function() {
      var databaseObject, key, ref, value;
      databaseObject = {};
      ref = this.attributes;
      for (key in ref) {
        value = ref[key];
        if (this[key] !== void 0 && value.attributes.dbField && !value.attributes.abstract) {
          databaseObject[value.attributes.dbField] = value.attributes.set != null ? value.attributes.set(this) : this[key];
        }
      }
      return databaseObject;
    };

    BaseModel.prototype.get = function(key, toObject) {
      var lookup;
      if (key in this.attributes) {
        if (this.attributes[key].attributes.get != null) {
          return this.attributes[key].attributes.get(this);
        } else {
          if (this.attributes[key] instanceof ForeignKey && (this[key] != null)) {
            lookup = {};
            lookup[this.attributes[key].attributes.referenceField] = this[key];
            return this.attributes[key].attributes.referenceModel.objects().get({
              lookup: lookup,
              toObject: toObject
            }).then(function(result) {
              return result;
            })["catch"](function(error) {
              throw error;
            });
          } else {
            return this[key];
          }
        }
      } else {
        throw new TypeError("The '" + key + "' field does not match any attribute of model " + this.constructor.metadata.model + "!");
      }
    };

    BaseModel.prototype.set = function(properties) {
      return _.each(properties, (function(_this) {
        return function(value, key) {
          if (key in _this.attributes) {
            return _this[key] = value;
          } else {
            throw new TypeError("The '" + key + "' field does not match any attribute of model " + _this.constructor.metadata.model + "!");
          }
        };
      })(this));
    };

    BaseModel.prototype.toJSON = function(arg) {
      var attributes, jsonObject;
      attributes = (arg != null ? arg : {}).attributes;
      if (attributes == null) {
        attributes = _.keys(this.attributes);
      }
      jsonObject = {};
      _.each(attributes, (function(_this) {
        return function(key, val) {
          if (!(_this.attributes[key] instanceof ManyToMany) && !(_this.attributes[key] instanceof ManyToOne)) {
            if (_this.attributes[key] instanceof ForeignKey) {
              return jsonObject[key] = _this[key];
            } else {
              return jsonObject[key] = _this.get(key) !== void 0 ? _this.get(key) : void 0;
            }
          }
        };
      })(this));
      return jsonObject;
    };

    BaseModel.prototype.validate = function(arg) {
      var promises, trx;
      trx = (arg != null ? arg : {}).trx;
      promises = [];
      _.each(this.attributes, (function(_this) {
        return function(value, key) {
          if (value.attributes.abstract == null) {
            return promises.push(value.validate(_this, {
              primaryKey: _this[_this.constructor.metadata.primaryKey],
              trx: trx
            }));
          }
        };
      })(this));
      return Promise.all(promises).then(function(values) {
        var validationResultObject;
        validationResultObject = {};
        _.each(_.compact(values), function(val, key) {
          return _.extend(validationResultObject, val);
        });
        return validationResultObject;
      });
    };

    BaseModel.prototype.save = function(arg) {
      var ref, returning, toObject;
      ref = arg != null ? arg : {}, returning = ref.returning, toObject = ref.toObject;
      return this.validate().then((function(_this) {
        return function(validationResult) {
          if (!(_.isEmpty(validationResult))) {
            throw validationResult;
          }
          if (_this[_this.constructor.metadata.primaryKey] != null) {
            return _this.constructor.objects().update({
              obj: _this,
              returning: returning,
              toObject: toObject
            }).then(function(res) {
              return res;
            });
          } else {
            return _this.constructor.objects().create({
              payload: _this._toDatabaseFields(),
              returning: returning,
              toObject: toObject
            }).then(function(res) {
              return res;
            });
          }
        };
      })(this))["catch"](function(error) {
        throw error;
      });
    };

    BaseModel.prototype["delete"] = function(whoDeleted) {
      var primaryKey;
      primaryKey = this.constructor.metadata.primaryKey;
      if (this[primaryKey] != null) {
        return this.constructor.objects()["delete"](this[primaryKey], whoDeleted).then(function(result) {
          return result;
        })["catch"](function(error) {
          throw error;
        });
      } else {
        throw new Error("This " + this.constructor.metadata.model + " does not have primary key set!");
      }
    };

    return BaseModel;

  })();

  module.exports = BaseModel;

}).call(this);
<|endoftext|>


<commit_before>module.exports = function(crowi) {
  var debug = require('debug')('crowi:models:bookmark')
  var mongoose = require('mongoose')
  var ObjectId = mongoose.Schema.Types.ObjectId
  var bookmarkSchema

  bookmarkSchema = new mongoose.Schema({
    page: { type: ObjectId, ref: 'Page', index: true },
    user: { type: ObjectId, ref: 'User', index: true },
    createdAt: { type: Date, default: Date.now() },
  })
  bookmarkSchema.index({ page: 1, user: 1 }, { unique: true })

  bookmarkSchema.statics.populatePage = function(bookmarks, requestUser) {
    var Bookmark = this
    var User = crowi.model('User')

    requestUser = requestUser || null

    // mongoose promise に置き換えてみたものの、こいつは not native promise but original promise だったので
    // これ以上は置き換えないことにする ...
    // @see http://eddywashere.com/blog/switching-out-callbacks-with-promises-in-mongoose/
    return Bookmark.populate(bookmarks, { path: 'page' })
      .then(function(bookmarks) {
        return Bookmark.populate(bookmarks, { path: 'page.revision', model: 'Revision' })
      })
      .then(function(bookmarks) {
        // hmm...
        bookmarks = bookmarks.filter(function(bookmark) {
          // requestUser を指定しない場合 public のみを返す
          if (requestUser === null) {
            return bookmark.page.isPublic()
          }

          return bookmark.page.isGrantedFor(requestUser)
        })

        return Bookmark.populate(bookmarks, {
          path: 'page.revision.author',
          model: 'User',
          select: User.USER_PUBLIC_FIELDS,
        })
      })
  }

  // bookmark チェック用
  bookmarkSchema.statics.findByPageIdAndUserId = function(pageId, userId) {
    var Bookmark = this

    return new Promise(function(resolve, reject) {
      return Bookmark.findOne({ page: pageId, user: userId }, function(err, doc) {
        if (err) {
          return reject(err)
        }

        return resolve(doc)
      })
    })
  }

  bookmarkSchema.statics.findByUserId = function(userId, option) {
    var Bookmark = this

    var limit = option.limit || 50
    var offset = option.offset || 0

    var finder = new Promise(function(resolve, reject) {
      Bookmark.find({ user: userId })
        .sort({ createdAt: -1 })
        .skip(offset)
        .limit(limit)
        .exec(function(err, bookmarks) {
          if (err) {
            return reject(err)
          }

          return Bookmark.populatePage(bookmarks).then(resolve)
        })
    })

    var counter = new Promise(function(resolve, reject) {
      Bookmark.count({ user: userId }).exec(function(err, count) {
        if (err) {
          return reject(err)
        }

        return resolve(count)
      })
    })

    return Promise.all([finder, counter])
      .then(function([bookmarks, count]) {
        return {
          meta: {
            total: count,
            limit: limit,
            offset: offset,
          },
          data: bookmarks,
        }
      })
      .catch(function(err) {
        debug('err', err)
        throw err
      })
  }

  // bookmark count
  bookmarkSchema.statics.countByPageId = async function(pageId) {
    const Bookmark = this
    const count = await Bookmark.count({ page: pageId })

    return count
  }

  /**
   * option = {
   *  limit: Int
   *  offset: Int
   *  requestUser: User
   * }
   */
  bookmarkSchema.statics.findByUser = function(user, option) {
    var Bookmark = this
    var requestUser = option.requestUser || null

    var limit = option.limit || 50
    var offset = option.offset || 0
    var populatePage = option.populatePage || false

    return new Promise(function(resolve, reject) {
      Bookmark.find({ user: user._id })
        .sort({ createdAt: -1 })
        .skip(offset)
        .limit(limit)
        .exec(function(err, bookmarks) {
          if (err) {
            return reject(err)
          }

          if (!populatePage) {
            return resolve(bookmarks)
          }

          return Bookmark.populatePage(bookmarks, requestUser).then(resolve)
        })
    })
  }

  bookmarkSchema.statics.add = async function(page, user) {
    const Bookmark = this

    const newBookmark = new Bookmark({ page, user, createdAt: Date.now() })
    debug('Bookmark.save', err, user.username, page.path)

    try {
      const bookmark = await newBookmark.save()
      return bookmark
    } catch (err) {
      if (err.code === 11000) {
        // duplicate key (dummy response of new object)
        return newBookmark
      }
      throw err
    }
  }

  bookmarkSchema.statics.removeBookmarksByPageId = async function(pageId) {
    const Bookmark = this

    try {
      const data = await Bookmark.remove({ page: pageId })
      return data
    } catch (err) {
      debug('Bookmark.remove failed (removeBookmarkByPage)', err)
      throw err
    }
  }

  bookmarkSchema.statics.removeBookmark = async function(page, user) {
    const Bookmark = this

    try {
      const data = await Bookmark.findOneAndRemove({ page, user })
      return data
    } catch (err) {
      debug('Bookmark.findOneAndRemove failed', err)
      throw err
    }
  }

  return mongoose.model('Bookmark', bookmarkSchema)
}
<commit_msg>Now, Mongoose.Promise is equivalent to global.Promise<commit_after>module.exports = function(crowi) {
  var debug = require('debug')('crowi:models:bookmark')
  var mongoose = require('mongoose')
  var ObjectId = mongoose.Schema.Types.ObjectId
  var bookmarkSchema

  bookmarkSchema = new mongoose.Schema({
    page: { type: ObjectId, ref: 'Page', index: true },
    user: { type: ObjectId, ref: 'User', index: true },
    createdAt: { type: Date, default: Date.now() },
  })
  bookmarkSchema.index({ page: 1, user: 1 }, { unique: true })

  bookmarkSchema.statics.populatePage = function(bookmarks, requestUser) {
    var Bookmark = this
    var User = crowi.model('User')

    requestUser = requestUser || null

    return Bookmark.populate(bookmarks, { path: 'page' })
      .then(function(bookmarks) {
        return Bookmark.populate(bookmarks, { path: 'page.revision', model: 'Revision' })
      })
      .then(function(bookmarks) {
        // hmm...
        bookmarks = bookmarks.filter(function(bookmark) {
          // requestUser を指定しない場合 public のみを返す
          if (requestUser === null) {
            return bookmark.page.isPublic()
          }

          return bookmark.page.isGrantedFor(requestUser)
        })

        return Bookmark.populate(bookmarks, {
          path: 'page.revision.author',
          model: 'User',
          select: User.USER_PUBLIC_FIELDS,
        })
      })
  }

  // bookmark チェック用
  bookmarkSchema.statics.findByPageIdAndUserId = function(pageId, userId) {
    var Bookmark = this

    return new Promise(function(resolve, reject) {
      return Bookmark.findOne({ page: pageId, user: userId }, function(err, doc) {
        if (err) {
          return reject(err)
        }

        return resolve(doc)
      })
    })
  }

  bookmarkSchema.statics.findByUserId = function(userId, option) {
    var Bookmark = this

    var limit = option.limit || 50
    var offset = option.offset || 0

    var finder = new Promise(function(resolve, reject) {
      Bookmark.find({ user: userId })
        .sort({ createdAt: -1 })
        .skip(offset)
        .limit(limit)
        .exec(function(err, bookmarks) {
          if (err) {
            return reject(err)
          }

          return Bookmark.populatePage(bookmarks).then(resolve)
        })
    })

    var counter = new Promise(function(resolve, reject) {
      Bookmark.count({ user: userId }).exec(function(err, count) {
        if (err) {
          return reject(err)
        }

        return resolve(count)
      })
    })

    return Promise.all([finder, counter])
      .then(function([bookmarks, count]) {
        return {
          meta: {
            total: count,
            limit: limit,
            offset: offset,
          },
          data: bookmarks,
        }
      })
      .catch(function(err) {
        debug('err', err)
        throw err
      })
  }

  // bookmark count
  bookmarkSchema.statics.countByPageId = async function(pageId) {
    const Bookmark = this
    const count = await Bookmark.count({ page: pageId })

    return count
  }

  /**
   * option = {
   *  limit: Int
   *  offset: Int
   *  requestUser: User
   * }
   */
  bookmarkSchema.statics.findByUser = function(user, option) {
    var Bookmark = this
    var requestUser = option.requestUser || null

    var limit = option.limit || 50
    var offset = option.offset || 0
    var populatePage = option.populatePage || false

    return new Promise(function(resolve, reject) {
      Bookmark.find({ user: user._id })
        .sort({ createdAt: -1 })
        .skip(offset)
        .limit(limit)
        .exec(function(err, bookmarks) {
          if (err) {
            return reject(err)
          }

          if (!populatePage) {
            return resolve(bookmarks)
          }

          return Bookmark.populatePage(bookmarks, requestUser).then(resolve)
        })
    })
  }

  bookmarkSchema.statics.add = async function(page, user) {
    const Bookmark = this

    const newBookmark = new Bookmark({ page, user, createdAt: Date.now() })
    debug('Bookmark.save', err, user.username, page.path)

    try {
      const bookmark = await newBookmark.save()
      return bookmark
    } catch (err) {
      if (err.code === 11000) {
        // duplicate key (dummy response of new object)
        return newBookmark
      }
      throw err
    }
  }

  bookmarkSchema.statics.removeBookmarksByPageId = async function(pageId) {
    const Bookmark = this

    try {
      const data = await Bookmark.remove({ page: pageId })
      return data
    } catch (err) {
      debug('Bookmark.remove failed (removeBookmarkByPage)', err)
      throw err
    }
  }

  bookmarkSchema.statics.removeBookmark = async function(page, user) {
    const Bookmark = this

    try {
      const data = await Bookmark.findOneAndRemove({ page, user })
      return data
    } catch (err) {
      debug('Bookmark.findOneAndRemove failed', err)
      throw err
    }
  }

  return mongoose.model('Bookmark', bookmarkSchema)
}
<|endoftext|>


<commit_before>'use strict';
const os = require('os');
const path = require('path');
const arrify = require('arrify');
const mergeWith = require('lodash.mergewith');
const multimatch = require('multimatch');
const pathExists = require('path-exists');
const pkgConf = require('pkg-conf');
const resolveFrom = require('resolve-from');
const prettier = require('prettier');
const semver = require('semver');

const DEFAULT_IGNORE = [
	'**/node_modules/**',
	'**/bower_components/**',
	'flow-typed/**',
	'coverage/**',
	'{tmp,temp}/**',
	'**/*.min.js',
	'**/bundle.js',
	'fixture{-*,}.{js,jsx}',
	'fixture{s,}/**',
	'{test,tests,spec,__tests__}/fixture{s,}/**',
	'vendor/**',
	'dist/**'
];

const DEFAULT_EXTENSION = [
	'js',
	'jsx',
	'ts',
	'tsx'
];

const DEFAULT_CONFIG = {
	useEslintrc: false,
	cache: true,
	cacheLocation: path.join(os.homedir() || os.tmpdir(), '.xo-cache/'),
	baseConfig: {
		extends: [
			'xo',
			path.join(__dirname, '../config/overrides.js'),
			path.join(__dirname, '../config/plugins.js')
		]
	}
};

/**
 * Define the rules that are enabled only for specific version of Node, based on `engines.node` in package.json or the `node-version` option.
 *
 * The keys are rule names and the values are an Object with a valid semver (`4.0.0` is valid `4` is not) as keys and the rule configuration as values.
 * Each entry define the rule configuration and the minimum Node version for which to set it.
 * The entry with the highest version that is compliant with the `engines.node`/`node-version` range will be used.
 *
 * @type {Object}
 *
 * @example
 * ```javascript
 * {
 * 	'plugin/rule': {
 * 		'6.0.0': ['error', {prop: 'node-6-conf'}],
 * 		'8.0.0': ['error', {prop: 'node-8-conf'}]
 * 	}
 * }
 *```
 * With `engines.node` set to `>=4` the rule `plugin/rule` will not be used.
 * With `engines.node` set to `>=6` the rule `plugin/rule` will be used with the config `{prop: 'node-6-conf'}`.
 * With `engines.node` set to `>=8` the rule `plugin/rule` will be used with the config `{prop: 'node-8-conf'}`.
 */
const ENGINE_RULES = {
	'promise/prefer-await-to-then': {
		'7.6.0': 'error'
	}
};

// Keep the same behaviour in mergeWith as deepAssign
const mergeFn = (prev, val) => {
	if (Array.isArray(prev) && Array.isArray(val)) {
		return val;
	}
};

const normalizeOpts = opts => {
	opts = Object.assign({}, opts);

	// Aliases for humans
	const aliases = [
		'env',
		'global',
		'ignore',
		'plugin',
		'rule',
		'setting',
		'extend',
		'extension'
	];

	for (const singular of aliases) {
		const plural = singular + 's';
		let value = opts[plural] || opts[singular];

		delete opts[singular];

		if (value === undefined) {
			continue;
		}

		if (singular !== 'rule' && singular !== 'setting') {
			value = arrify(value);
		}

		opts[plural] = value;
	}

	return opts;
};

const mergeWithPkgConf = opts => {
	opts = Object.assign({cwd: process.cwd()}, opts);
	opts.cwd = path.resolve(opts.cwd);
	const conf = pkgConf.sync('xo', {cwd: opts.cwd, skipOnFalse: true});
	const engines = pkgConf.sync('engines', {cwd: opts.cwd});
	return Object.assign({}, conf, {engines}, opts);
};

const normalizeSpaces = opts => typeof opts.space === 'number' ? opts.space : 2;

const mergeWithPrettierConf = (opts, prettierOpts) => {
	if ((opts.semicolon === true && prettierOpts.semi === false) ||
		(opts.semicolon === false && prettierOpts.semi === true)) {
		throw new Error(`The Prettier config \`semi\` is ${prettierOpts.semi} while XO \`semicolon\` is ${opts.semicolon}`);
	}

	if (((opts.space === true || typeof opts.space === 'number') && prettierOpts.useTabs === true) ||
		((opts.space === false) && prettierOpts.useTabs === false)) {
		throw new Error(`The Prettier config \`useTabs\` is ${prettierOpts.useTabs} while XO \`space\` is ${opts.space}`);
	}

	if (typeof opts.space === 'number' && typeof prettierOpts.tabWidth === 'number' && opts.space !== prettierOpts.tabWidth) {
		throw new Error(`The Prettier config \`tabWidth\` is ${prettierOpts.tabWidth} while XO \`space\` is ${opts.space}`);
	}

	return mergeWith(
		{},
		{
			singleQuote: true,
			bracketSpacing: false,
			jsxBracketSameLine: false,
			trailingComma: 'none',
			tabWidth: normalizeSpaces(opts),
			useTabs: !opts.space,
			semi: opts.semicolon !== false
		},
		prettierOpts,
		mergeFn
	);
};

// Define the shape of deep properties for mergeWith
const emptyOptions = () => ({
	rules: {},
	settings: {},
	globals: [],
	envs: [],
	plugins: [],
	extends: []
});

const buildConfig = opts => {
	const config = mergeWith(
		emptyOptions(),
		DEFAULT_CONFIG,
		opts,
		mergeFn
	);
	const spaces = normalizeSpaces(opts);

	if (opts.engines && opts.engines.node && semver.validRange(opts.engines.node)) {
		for (const rule of Object.keys(ENGINE_RULES)) {
			// Use the rule value for the highest version that is lower or equal to the oldest version of Node.js supported
			for (const minVersion of Object.keys(ENGINE_RULES[rule]).sort(semver.compare)) {
				if (!semver.intersects(opts.engines.node, `<${minVersion}`)) {
					config.rules[rule] = ENGINE_RULES[rule][minVersion];
				}
			}
		}
	}

	if (opts.space && !opts.prettier) {
		config.rules.indent = ['error', spaces, {SwitchCase: 1}];

		// Only apply if the user has the React plugin
		if (opts.cwd && resolveFrom.silent(opts.cwd, 'eslint-plugin-react')) {
			config.plugins = config.plugins.concat('react');
			config.rules['react/jsx-indent-props'] = ['error', spaces];
			config.rules['react/jsx-indent'] = ['error', spaces];
		}
	}

	if (opts.semicolon === false && !opts.prettier) {
		config.rules.semi = ['error', 'never'];
		config.rules['semi-spacing'] = ['error', {
			before: false,
			after: true
		}];
	}

	if (opts.esnext !== false) {
		config.baseConfig.extends = [
			'xo/esnext',
			path.join(__dirname, '../config/plugins.js')
		];
	}

	if (opts.rules) {
		Object.assign(config.rules, opts.rules);
	}

	if (opts.settings) {
		config.baseConfig.settings = opts.settings;
	}

	if (opts.parser) {
		config.baseConfig.parser = opts.parser;
	}

	if (opts.extends && opts.extends.length > 0) {
		// TODO: This logic needs to be improved, preferably use the same code as ESLint
		// user's configs must be resolved to their absolute paths
		const configs = opts.extends.map(name => {
			// Don't do anything if it's a filepath
			if (pathExists.sync(name)) {
				return name;
			}

			// Don't do anything if it's a config from a plugin
			if (name.startsWith('plugin:')) {
				return name;
			}

			if (!name.includes('eslint-config-')) {
				name = `eslint-config-${name}`;
			}

			const ret = resolveFrom(opts.cwd, name);

			if (!ret) {
				throw new Error(`Couldn't find ESLint config: ${name}`);
			}

			return ret;
		});

		config.baseConfig.extends = config.baseConfig.extends.concat(configs);
	}

	// If the user sets the `prettier` options then add the `prettier` plugin and config
	if (opts.prettier) {
		// Disable formatting rules conflicting with Prettier
		config.rules['unicorn/number-literal-case'] = 'off';
		// The prettier plugin uses Prettier to format the code with `--fix`
		config.plugins = config.plugins.concat('prettier');
		// The prettier config overrides ESLint stylistic rules that are handled by Prettier
		config.baseConfig.extends = config.baseConfig.extends.concat('prettier');
		// The `prettier/prettier` rule reports errors if the code is not formatted in accordance to Prettier
		config.rules['prettier/prettier'] = [
			'error', mergeWithPrettierConf(opts, prettier.resolveConfig.sync(opts.cwd || process.cwd()) || {})
		];
		// If the user has the React, Flowtype or Standard plugin, add the corresponding Prettier rule overrides
		// See https://github.com/prettier/eslint-config-prettier for the list of plugins overrrides
		for (const override of ['react', 'flowtype', 'standard']) {
			if (opts.cwd && resolveFrom.silent(opts.cwd, `eslint-plugin-${override}`)) {
				config.baseConfig.extends = config.baseConfig.extends.concat(`prettier/${override}`);
			}
		}
	}

	return config;
};

// Builds a list of overrides for a particular path, and a hash value.
// The hash value is a binary representation of which elements in the `overrides` array apply to the path.
//
// If overrides.length === 4, and only the first and third elements apply, then our hash is: 1010 (in binary)
const findApplicableOverrides = (path, overrides) => {
	let hash = 0;
	const applicable = [];

	for (const override of overrides) {
		hash <<= 1;

		if (multimatch(path, override.files).length > 0) {
			applicable.push(override);
			hash |= 1;
		}
	}

	return {
		hash,
		applicable
	};
};

const mergeApplicableOverrides = (baseOptions, applicableOverrides) => {
	applicableOverrides = applicableOverrides.map(override => normalizeOpts(override));
	const overrides = [emptyOptions(), baseOptions].concat(applicableOverrides, mergeFn);
	return mergeWith(...overrides);
};

// Creates grouped sets of merged options together with the paths they apply to.
const groupConfigs = (paths, baseOptions, overrides) => {
	const map = {};
	const arr = [];

	for (const x of paths) {
		const data = findApplicableOverrides(x, overrides);

		if (!map[data.hash]) {
			const mergedOpts = mergeApplicableOverrides(baseOptions, data.applicable);
			delete mergedOpts.files;

			arr.push(map[data.hash] = {
				opts: mergedOpts,
				paths: []
			});
		}

		map[data.hash].paths.push(x);
	}

	return arr;
};

const getIgnores = opts => {
	opts.ignores = DEFAULT_IGNORE.concat(opts.ignores || []);
	return opts;
};

const preprocess = opts => {
	opts = mergeWithPkgConf(opts);
	opts = normalizeOpts(opts);
	opts = getIgnores(opts);
	opts.extensions = DEFAULT_EXTENSION.concat(opts.extensions || []);

	return opts;
};

module.exports.DEFAULT_IGNORE = DEFAULT_IGNORE;
module.exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
module.exports.mergeWithPkgConf = mergeWithPkgConf;
module.exports.mergeWithPrettierConf = mergeWithPrettierConf;
module.exports.normalizeOpts = normalizeOpts;
module.exports.buildConfig = buildConfig;
module.exports.findApplicableOverrides = findApplicableOverrides;
module.exports.mergeApplicableOverrides = mergeApplicableOverrides;
module.exports.groupConfigs = groupConfigs;
module.exports.preprocess = preprocess;
module.exports.emptyOptions = emptyOptions;
module.exports.getIgnores = getIgnores;
<commit_msg>Don't ignore fixture directories by default (#317)<commit_after>'use strict';
const os = require('os');
const path = require('path');
const arrify = require('arrify');
const mergeWith = require('lodash.mergewith');
const multimatch = require('multimatch');
const pathExists = require('path-exists');
const pkgConf = require('pkg-conf');
const resolveFrom = require('resolve-from');
const prettier = require('prettier');
const semver = require('semver');

const DEFAULT_IGNORE = [
	'**/node_modules/**',
	'**/bower_components/**',
	'flow-typed/**',
	'coverage/**',
	'{tmp,temp}/**',
	'**/*.min.js',
	'**/bundle.js',
	'vendor/**',
	'dist/**'
];

const DEFAULT_EXTENSION = [
	'js',
	'jsx',
	'ts',
	'tsx'
];

const DEFAULT_CONFIG = {
	useEslintrc: false,
	cache: true,
	cacheLocation: path.join(os.homedir() || os.tmpdir(), '.xo-cache/'),
	baseConfig: {
		extends: [
			'xo',
			path.join(__dirname, '../config/overrides.js'),
			path.join(__dirname, '../config/plugins.js')
		]
	}
};

/**
 * Define the rules that are enabled only for specific version of Node, based on `engines.node` in package.json or the `node-version` option.
 *
 * The keys are rule names and the values are an Object with a valid semver (`4.0.0` is valid `4` is not) as keys and the rule configuration as values.
 * Each entry define the rule configuration and the minimum Node version for which to set it.
 * The entry with the highest version that is compliant with the `engines.node`/`node-version` range will be used.
 *
 * @type {Object}
 *
 * @example
 * ```javascript
 * {
 * 	'plugin/rule': {
 * 		'6.0.0': ['error', {prop: 'node-6-conf'}],
 * 		'8.0.0': ['error', {prop: 'node-8-conf'}]
 * 	}
 * }
 *```
 * With `engines.node` set to `>=4` the rule `plugin/rule` will not be used.
 * With `engines.node` set to `>=6` the rule `plugin/rule` will be used with the config `{prop: 'node-6-conf'}`.
 * With `engines.node` set to `>=8` the rule `plugin/rule` will be used with the config `{prop: 'node-8-conf'}`.
 */
const ENGINE_RULES = {
	'promise/prefer-await-to-then': {
		'7.6.0': 'error'
	}
};

// Keep the same behaviour in mergeWith as deepAssign
const mergeFn = (prev, val) => {
	if (Array.isArray(prev) && Array.isArray(val)) {
		return val;
	}
};

const normalizeOpts = opts => {
	opts = Object.assign({}, opts);

	// Aliases for humans
	const aliases = [
		'env',
		'global',
		'ignore',
		'plugin',
		'rule',
		'setting',
		'extend',
		'extension'
	];

	for (const singular of aliases) {
		const plural = singular + 's';
		let value = opts[plural] || opts[singular];

		delete opts[singular];

		if (value === undefined) {
			continue;
		}

		if (singular !== 'rule' && singular !== 'setting') {
			value = arrify(value);
		}

		opts[plural] = value;
	}

	return opts;
};

const mergeWithPkgConf = opts => {
	opts = Object.assign({cwd: process.cwd()}, opts);
	opts.cwd = path.resolve(opts.cwd);
	const conf = pkgConf.sync('xo', {cwd: opts.cwd, skipOnFalse: true});
	const engines = pkgConf.sync('engines', {cwd: opts.cwd});
	return Object.assign({}, conf, {engines}, opts);
};

const normalizeSpaces = opts => typeof opts.space === 'number' ? opts.space : 2;

const mergeWithPrettierConf = (opts, prettierOpts) => {
	if ((opts.semicolon === true && prettierOpts.semi === false) ||
		(opts.semicolon === false && prettierOpts.semi === true)) {
		throw new Error(`The Prettier config \`semi\` is ${prettierOpts.semi} while XO \`semicolon\` is ${opts.semicolon}`);
	}

	if (((opts.space === true || typeof opts.space === 'number') && prettierOpts.useTabs === true) ||
		((opts.space === false) && prettierOpts.useTabs === false)) {
		throw new Error(`The Prettier config \`useTabs\` is ${prettierOpts.useTabs} while XO \`space\` is ${opts.space}`);
	}

	if (typeof opts.space === 'number' && typeof prettierOpts.tabWidth === 'number' && opts.space !== prettierOpts.tabWidth) {
		throw new Error(`The Prettier config \`tabWidth\` is ${prettierOpts.tabWidth} while XO \`space\` is ${opts.space}`);
	}

	return mergeWith(
		{},
		{
			singleQuote: true,
			bracketSpacing: false,
			jsxBracketSameLine: false,
			trailingComma: 'none',
			tabWidth: normalizeSpaces(opts),
			useTabs: !opts.space,
			semi: opts.semicolon !== false
		},
		prettierOpts,
		mergeFn
	);
};

// Define the shape of deep properties for mergeWith
const emptyOptions = () => ({
	rules: {},
	settings: {},
	globals: [],
	envs: [],
	plugins: [],
	extends: []
});

const buildConfig = opts => {
	const config = mergeWith(
		emptyOptions(),
		DEFAULT_CONFIG,
		opts,
		mergeFn
	);
	const spaces = normalizeSpaces(opts);

	if (opts.engines && opts.engines.node && semver.validRange(opts.engines.node)) {
		for (const rule of Object.keys(ENGINE_RULES)) {
			// Use the rule value for the highest version that is lower or equal to the oldest version of Node.js supported
			for (const minVersion of Object.keys(ENGINE_RULES[rule]).sort(semver.compare)) {
				if (!semver.intersects(opts.engines.node, `<${minVersion}`)) {
					config.rules[rule] = ENGINE_RULES[rule][minVersion];
				}
			}
		}
	}

	if (opts.space && !opts.prettier) {
		config.rules.indent = ['error', spaces, {SwitchCase: 1}];

		// Only apply if the user has the React plugin
		if (opts.cwd && resolveFrom.silent(opts.cwd, 'eslint-plugin-react')) {
			config.plugins = config.plugins.concat('react');
			config.rules['react/jsx-indent-props'] = ['error', spaces];
			config.rules['react/jsx-indent'] = ['error', spaces];
		}
	}

	if (opts.semicolon === false && !opts.prettier) {
		config.rules.semi = ['error', 'never'];
		config.rules['semi-spacing'] = ['error', {
			before: false,
			after: true
		}];
	}

	if (opts.esnext !== false) {
		config.baseConfig.extends = [
			'xo/esnext',
			path.join(__dirname, '../config/plugins.js')
		];
	}

	if (opts.rules) {
		Object.assign(config.rules, opts.rules);
	}

	if (opts.settings) {
		config.baseConfig.settings = opts.settings;
	}

	if (opts.parser) {
		config.baseConfig.parser = opts.parser;
	}

	if (opts.extends && opts.extends.length > 0) {
		// TODO: This logic needs to be improved, preferably use the same code as ESLint
		// user's configs must be resolved to their absolute paths
		const configs = opts.extends.map(name => {
			// Don't do anything if it's a filepath
			if (pathExists.sync(name)) {
				return name;
			}

			// Don't do anything if it's a config from a plugin
			if (name.startsWith('plugin:')) {
				return name;
			}

			if (!name.includes('eslint-config-')) {
				name = `eslint-config-${name}`;
			}

			const ret = resolveFrom(opts.cwd, name);

			if (!ret) {
				throw new Error(`Couldn't find ESLint config: ${name}`);
			}

			return ret;
		});

		config.baseConfig.extends = config.baseConfig.extends.concat(configs);
	}

	// If the user sets the `prettier` options then add the `prettier` plugin and config
	if (opts.prettier) {
		// Disable formatting rules conflicting with Prettier
		config.rules['unicorn/number-literal-case'] = 'off';
		// The prettier plugin uses Prettier to format the code with `--fix`
		config.plugins = config.plugins.concat('prettier');
		// The prettier config overrides ESLint stylistic rules that are handled by Prettier
		config.baseConfig.extends = config.baseConfig.extends.concat('prettier');
		// The `prettier/prettier` rule reports errors if the code is not formatted in accordance to Prettier
		config.rules['prettier/prettier'] = [
			'error', mergeWithPrettierConf(opts, prettier.resolveConfig.sync(opts.cwd || process.cwd()) || {})
		];
		// If the user has the React, Flowtype or Standard plugin, add the corresponding Prettier rule overrides
		// See https://github.com/prettier/eslint-config-prettier for the list of plugins overrrides
		for (const override of ['react', 'flowtype', 'standard']) {
			if (opts.cwd && resolveFrom.silent(opts.cwd, `eslint-plugin-${override}`)) {
				config.baseConfig.extends = config.baseConfig.extends.concat(`prettier/${override}`);
			}
		}
	}

	return config;
};

// Builds a list of overrides for a particular path, and a hash value.
// The hash value is a binary representation of which elements in the `overrides` array apply to the path.
//
// If overrides.length === 4, and only the first and third elements apply, then our hash is: 1010 (in binary)
const findApplicableOverrides = (path, overrides) => {
	let hash = 0;
	const applicable = [];

	for (const override of overrides) {
		hash <<= 1;

		if (multimatch(path, override.files).length > 0) {
			applicable.push(override);
			hash |= 1;
		}
	}

	return {
		hash,
		applicable
	};
};

const mergeApplicableOverrides = (baseOptions, applicableOverrides) => {
	applicableOverrides = applicableOverrides.map(override => normalizeOpts(override));
	const overrides = [emptyOptions(), baseOptions].concat(applicableOverrides, mergeFn);
	return mergeWith(...overrides);
};

// Creates grouped sets of merged options together with the paths they apply to.
const groupConfigs = (paths, baseOptions, overrides) => {
	const map = {};
	const arr = [];

	for (const x of paths) {
		const data = findApplicableOverrides(x, overrides);

		if (!map[data.hash]) {
			const mergedOpts = mergeApplicableOverrides(baseOptions, data.applicable);
			delete mergedOpts.files;

			arr.push(map[data.hash] = {
				opts: mergedOpts,
				paths: []
			});
		}

		map[data.hash].paths.push(x);
	}

	return arr;
};

const getIgnores = opts => {
	opts.ignores = DEFAULT_IGNORE.concat(opts.ignores || []);
	return opts;
};

const preprocess = opts => {
	opts = mergeWithPkgConf(opts);
	opts = normalizeOpts(opts);
	opts = getIgnores(opts);
	opts.extensions = DEFAULT_EXTENSION.concat(opts.extensions || []);

	return opts;
};

module.exports.DEFAULT_IGNORE = DEFAULT_IGNORE;
module.exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
module.exports.mergeWithPkgConf = mergeWithPkgConf;
module.exports.mergeWithPrettierConf = mergeWithPrettierConf;
module.exports.normalizeOpts = normalizeOpts;
module.exports.buildConfig = buildConfig;
module.exports.findApplicableOverrides = findApplicableOverrides;
module.exports.mergeApplicableOverrides = mergeApplicableOverrides;
module.exports.groupConfigs = groupConfigs;
module.exports.preprocess = preprocess;
module.exports.emptyOptions = emptyOptions;
module.exports.getIgnores = getIgnores;
<|endoftext|>


<commit_before>//
// # RequestEmitter
//

//
// ## Error Handling
//
// All of the error handling for RequestEmitters is facilitated by the callback functions its methods accept.
//
var EventEmitter = require('events').EventEmitter
  , url = require('url')
  , debug = require('debug')('shuttle:RequestEmitter')
  , zmqstream = require('zmq-stream')

//
// ## RequestEmitter `RequestEmitter(options)`
//
// Creates a new RequestEmitter with the specified options:
//
//  * `timeout`: A duration, in ms, that the RequestEmitter will wait for a response before retrying or raising an
//  Error. If zero, no timeout mechanism will be used. If requests can not be guaranteed to be idempotent, `timeout` and
//  `retries` should not be used. Defaults to 0 to keep from unduly making this guarantee.
//  * `retries`: A number of times that the RequestEmitter will automatically retry a request that has timed out before
//  raising an Error. If zero, no retries will be made, even if `timeout` is defined. If requests can not be guaranteed
//  to be idempotent, `timeout` and `retries` should not be used. Defaults to 3, which is an arbitrarily-chosen number.
//  * `linger`: A duration, in ms, that the RequestEmitter will wait for outgoing messages to be sent before releasing
//  its resources after `close` is called. Outgoing messages take a non-zero time to be completely sent, and can be
//  dropped by a subsequent call to `close`. A value of -1 indicates an infinite delay. Defaults to 0.
//
function RequestEmitter(obj) {
  obj = obj || {}

  this.timeout = (typeof obj.timeout === 'number') ? obj.timeout : 0
  this.retries = (typeof obj.retries === 'number') ? obj.timeout : 3
  this.linger = (typeof obj.linger === 'number') ? obj.linger : 0

  this._nextRequestId = 0
  this._pending = {}
  this._zdealer = null
}

//
// ## emit `emit(name, data, callback)`
//
// Emits an event (request) named **name**, along with **data**, over the Shuttle mesh, to be handled by some
// RequestHandler. If successful, **Callback** will receive the result of the request. Otherwise, **callback** will
// receive the error.
//
// If the request times out (as defined by `RequestEmitter.timeout` and `RequestEmitter.retries`), **callback** will
// receive a TimeoutError.
//
// NOTE: Do not try to call other EventEmitter methods like `on`. It won't work.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.emit = emit
function emit(name, data, callback) {
  var self = this

  if (name === 'newListener') {
    return EventEmitter.prototype.emit.call(this, name, data)
  }

  self._emitAndRetry(name, data, callback, self.retries)

  return self
}

//
// ## listen `listen(options)`
//
// ### Also `listenForRequests`
//
// Synchronously listens for RequestHandler connections. If **options.url** is provided, that URL will be used.
// Otherwise, **options** will be formatted as a URL as defined by the core `url` module.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.listenForRequests = listen
RequestEmitter.prototype.listen = listen
function listen(options) {
  var self = this
    , opts = options || {}
    , iface = options.url

  if (!iface) {
    iface = url.format(opts)
  }

  debug('Listening to %s.', iface)

  self._initSocket()
  self._zdealer.bind(iface)

  return self
}

//
// ## connect `connect(options)`
//
// ### Also `connectForRequests`
//
// Synchronously connects to a listening RequestHandler. If **options.url** is provided, that URL will be used.
// Otherwise, **options** will be formatted as a URL as defined by the core `url` module.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.connectForRequests = connect
RequestEmitter.prototype.connect = connect
function connect(options) {
  var self = this
    , opts = options || {}
    , iface = options.url

  if (!iface) {
    iface = url.format(opts)
  }

  debug('Connecting to %s.', iface)

  self._initSocket()
  self._zdealer.connect(iface)

  return self
}

//
// ## close `close()`
//
// Synchonously releases the underlying resources, allowing the RequestEmitter to be `connect`ed or `listen`ed again
// freely.
//
// Unless the RequestEmitter was configured with a `linger` period, all pending outgoing messages will be dropped.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.close = close
function close() {
  var self = this

  if (!self._zdealer) {
    return
  }

  debug('Closing.')

  self._zdealer.close()
  self._zdealer = null

  return self
}

//
// ## _initSocket `_initSocket()`
//
// Internal use only.
//
// Creates the underlying networking resources.
//
RequestEmitter.prototype._initSocket = _initSocket
function _initSocket() {
  var self = this

  if (self._zdealer) {
    return
  }

  debug('Creating a new ZMQ socket.')

  self._zdealer = new zmqstream.Socket({
    type: zmqstream.Type.DEALER
  })

  self._zdealer.set(zmqstream.Option.LINGER, self.linger)

  self._zdealer.on('readable', function () {
    self._handleResponses()
  })
  self._handleResponses()
}

//
// ## _emitAndRetry `_emitAndRetry(name, data, callback, retries)`
//
// Internal use only.
//
// Sends a request across the network, retrying at most **retries** times.
//
RequestEmitter.prototype._emitAndRetry = _emitAndRetry
function _emitAndRetry(name, data, callback, retries) {
  var self = this
    , requestId = String(self._nextRequestId++)
    , payload
    , success

  self._pending[requestId] = {
    callback: (typeof callback === 'function') ? callback : null,
    timerId: null
  }

  payload = JSON.stringify({
    name: name,
    data: data
  })

  debug('Sending request for %s as request %s with %s.', name, requestId, payload)

  self._initSocket()
  success = self._zdealer.write([
    new Buffer(0),
    new Buffer(requestId),
    new Buffer(payload)
  ])

  if (typeof callback === 'function') {
    if (!success) {
      // TODO: Bubble up the internal 'drain' event?
      // TODO: Put some place safe.
      callback(new Error('Too many requests'))
      return
    }

    if (self.timeout > 0) {
      self._pending[requestId].timerId = setTimeout(
        function timeout() {
          debug('Timeout during request %s named %s. %s retries remaining.', requestId, name, retries - 1)

          ;delete self._pending[requestId]

          if (retries > 0) {
            self._emitAndRetry(name, data, callback, retries - 1)
          } else {
            callback(new Error('Timeout'))
          }
        },
        self.timeout
      )
    }
  }}

//
// ## _handleResponses `_handleResponses()`
//
// Internal use only.
//
// Polls the network for requests, re-emitting them locally for handling.
//
RequestEmitter.prototype._handleResponses = _handleResponses
function _handleResponses() {
  var self = this
    , messages = null
    , pending = null

  // 1. If the dealer socket is currently closed, it cannot be read from. Otherwise, read from it.
  if (!self._zdealer) {
    return
  }

  messages = self._zdealer.read(10)

  // 1. If there are no messages, we'll come back to this later. For now, just leave.
  if (!messages) {
    return
  }

  // 1. For each message, we want to look up the callback and fire it.
  messages.forEach(function (envelope) {
    var payload
      , requestId

    //    1. If we don't have three message frames or the body isn't valid JSON, this didn't come from a
    //    RequestHandler. It's safe to ignore.
    if (envelope.length !== 3) {
      return
    }

    try {
      payload = JSON.parse(envelope.pop().toString('utf8'))
    } catch (e) {
      return
    }

    requestId = String(envelope.pop())
    pending = self._pending[requestId]

    //    1. If we don't have a callback function, we assume it's meant to be a fire-and-forget event, so we'll ignore
    //    the response.
    if (!pending || !pending.callback) {
      return
    }

    debug('Receiving response to %s with (%s, %s).', requestId, payload.err, JSON.stringify(payload.data))

    clearTimeout(pending.timerId)
    pending.callback(payload.err, payload.data)
    ;delete self._pending[requestId]
  })

  // 1. We may have more messages to receive, so try reading again soon.
  process.nextTick(function () {
    self._handleResponses()
  })
}

module.exports = RequestEmitter
<commit_msg>Fixed  configurability.<commit_after>//
// # RequestEmitter
//

//
// ## Error Handling
//
// All of the error handling for RequestEmitters is facilitated by the callback functions its methods accept.
//
var EventEmitter = require('events').EventEmitter
  , url = require('url')
  , debug = require('debug')('shuttle:RequestEmitter')
  , zmqstream = require('zmq-stream')

//
// ## RequestEmitter `RequestEmitter(options)`
//
// Creates a new RequestEmitter with the specified options:
//
//  * `timeout`: A duration, in ms, that the RequestEmitter will wait for a response before retrying or raising an
//  Error. If zero, no timeout mechanism will be used. If requests can not be guaranteed to be idempotent, `timeout` and
//  `retries` should not be used. Defaults to 0 to keep from unduly making this guarantee.
//  * `retries`: A number of times that the RequestEmitter will automatically retry a request that has timed out before
//  raising an Error. If zero, no retries will be made, even if `timeout` is defined. If requests can not be guaranteed
//  to be idempotent, `timeout` and `retries` should not be used. Defaults to 3, which is an arbitrarily-chosen number.
//  * `linger`: A duration, in ms, that the RequestEmitter will wait for outgoing messages to be sent before releasing
//  its resources after `close` is called. Outgoing messages take a non-zero time to be completely sent, and can be
//  dropped by a subsequent call to `close`. A value of -1 indicates an infinite delay. Defaults to 0.
//
function RequestEmitter(obj) {
  obj = obj || {}

  this.timeout = (typeof obj.timeout === 'number') ? obj.timeout : 0
  this.retries = (typeof obj.retries === 'number') ? obj.retries : 3
  this.linger = (typeof obj.linger === 'number') ? obj.linger : 0

  this._nextRequestId = 0
  this._pending = {}
  this._zdealer = null
}

//
// ## emit `emit(name, data, callback)`
//
// Emits an event (request) named **name**, along with **data**, over the Shuttle mesh, to be handled by some
// RequestHandler. If successful, **Callback** will receive the result of the request. Otherwise, **callback** will
// receive the error.
//
// If the request times out (as defined by `RequestEmitter.timeout` and `RequestEmitter.retries`), **callback** will
// receive a TimeoutError.
//
// NOTE: Do not try to call other EventEmitter methods like `on`. It won't work.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.emit = emit
function emit(name, data, callback) {
  var self = this

  if (name === 'newListener') {
    return EventEmitter.prototype.emit.call(this, name, data)
  }

  self._emitAndRetry(name, data, callback, self.retries)

  return self
}

//
// ## listen `listen(options)`
//
// ### Also `listenForRequests`
//
// Synchronously listens for RequestHandler connections. If **options.url** is provided, that URL will be used.
// Otherwise, **options** will be formatted as a URL as defined by the core `url` module.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.listenForRequests = listen
RequestEmitter.prototype.listen = listen
function listen(options) {
  var self = this
    , opts = options || {}
    , iface = options.url

  if (!iface) {
    iface = url.format(opts)
  }

  debug('Listening to %s.', iface)

  self._initSocket()
  self._zdealer.bind(iface)

  return self
}

//
// ## connect `connect(options)`
//
// ### Also `connectForRequests`
//
// Synchronously connects to a listening RequestHandler. If **options.url** is provided, that URL will be used.
// Otherwise, **options** will be formatted as a URL as defined by the core `url` module.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.connectForRequests = connect
RequestEmitter.prototype.connect = connect
function connect(options) {
  var self = this
    , opts = options || {}
    , iface = options.url

  if (!iface) {
    iface = url.format(opts)
  }

  debug('Connecting to %s.', iface)

  self._initSocket()
  self._zdealer.connect(iface)

  return self
}

//
// ## close `close()`
//
// Synchonously releases the underlying resources, allowing the RequestEmitter to be `connect`ed or `listen`ed again
// freely.
//
// Unless the RequestEmitter was configured with a `linger` period, all pending outgoing messages will be dropped.
//
// Returns the RequestEmitter.
//
RequestEmitter.prototype.close = close
function close() {
  var self = this

  if (!self._zdealer) {
    return
  }

  debug('Closing.')

  self._zdealer.close()
  self._zdealer = null

  return self
}

//
// ## _initSocket `_initSocket()`
//
// Internal use only.
//
// Creates the underlying networking resources.
//
RequestEmitter.prototype._initSocket = _initSocket
function _initSocket() {
  var self = this

  if (self._zdealer) {
    return
  }

  debug('Creating a new ZMQ socket.')

  self._zdealer = new zmqstream.Socket({
    type: zmqstream.Type.DEALER
  })

  self._zdealer.set(zmqstream.Option.LINGER, self.linger)

  self._zdealer.on('readable', function () {
    self._handleResponses()
  })
  self._handleResponses()
}

//
// ## _emitAndRetry `_emitAndRetry(name, data, callback, retries)`
//
// Internal use only.
//
// Sends a request across the network, retrying at most **retries** times.
//
RequestEmitter.prototype._emitAndRetry = _emitAndRetry
function _emitAndRetry(name, data, callback, retries) {
  var self = this
    , requestId = String(self._nextRequestId++)
    , payload
    , success

  self._pending[requestId] = {
    callback: (typeof callback === 'function') ? callback : null,
    timerId: null
  }

  payload = JSON.stringify({
    name: name,
    data: data
  })

  debug('Sending request for %s as request %s with %s.', name, requestId, payload)

  self._initSocket()
  success = self._zdealer.write([
    new Buffer(0),
    new Buffer(requestId),
    new Buffer(payload)
  ])

  if (typeof callback === 'function') {
    if (!success) {
      // TODO: Bubble up the internal 'drain' event?
      // TODO: Put some place safe.
      callback(new Error('Too many requests'))
      return
    }

    if (self.timeout > 0) {
      self._pending[requestId].timerId = setTimeout(
        function timeout() {
          debug('Timeout during request %s named %s. %s retries remaining.', requestId, name, retries - 1)

          ;delete self._pending[requestId]

          if (retries > 0) {
            self._emitAndRetry(name, data, callback, retries - 1)
          } else {
            callback(new Error('Timeout'))
          }
        },
        self.timeout
      )
    }
  }}

//
// ## _handleResponses `_handleResponses()`
//
// Internal use only.
//
// Polls the network for requests, re-emitting them locally for handling.
//
RequestEmitter.prototype._handleResponses = _handleResponses
function _handleResponses() {
  var self = this
    , messages = null
    , pending = null

  // 1. If the dealer socket is currently closed, it cannot be read from. Otherwise, read from it.
  if (!self._zdealer) {
    return
  }

  messages = self._zdealer.read(10)

  // 1. If there are no messages, we'll come back to this later. For now, just leave.
  if (!messages) {
    return
  }

  // 1. For each message, we want to look up the callback and fire it.
  messages.forEach(function (envelope) {
    var payload
      , requestId

    //    1. If we don't have three message frames or the body isn't valid JSON, this didn't come from a
    //    RequestHandler. It's safe to ignore.
    if (envelope.length !== 3) {
      return
    }

    try {
      payload = JSON.parse(envelope.pop().toString('utf8'))
    } catch (e) {
      return
    }

    requestId = String(envelope.pop())
    pending = self._pending[requestId]

    //    1. If we don't have a callback function, we assume it's meant to be a fire-and-forget event, so we'll ignore
    //    the response.
    if (!pending || !pending.callback) {
      return
    }

    debug('Receiving response to %s with (%s, %s).', requestId, payload.err, JSON.stringify(payload.data))

    clearTimeout(pending.timerId)
    pending.callback(payload.err, payload.data)
    ;delete self._pending[requestId]
  })

  // 1. We may have more messages to receive, so try reading again soon.
  process.nextTick(function () {
    self._handleResponses()
  })
}

module.exports = RequestEmitter
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var BowerJson = require('../json/bower-json.js'),
    PackageJson = require('../json/package-json.js'),
    configJsonFactory = require('../json/config-json-factory.js');

function CheckIf() {}

CheckIf.prototype = {

  configJson: function (source, configManager) {
    if (configManager === 'bower') {
      this.bowerJson(source);
    } else if (configManager === 'npm') {
      this.packageJson(source);
    } else {
      throw new TypeError('Unknown configManager: ' + configManager, 'check-if.js');
    }
    return this;
  },

  /**
   * Adds readability to BowerJson filters.
   * If source param is a path, returns a new BowerJson object.
   * @param  {} source [description]
   * @return {BowerJson}        [description]
   */
  bowerJson: function checkIfBowerJson(source) {
    if (typeof source === 'undefined') {
      throw new Error('"source" param is required.', 'check-if.js');
    }
    if (source instanceof BowerJson) {
      this.configJsonObj = source;
    } else if (typeof source === 'string') {
      this.configJsonObj = configJsonFactory.createConfigJson('bower', source);
    } else {
      throw new TypeError('Unknown source: ' + source, 'check-if.js');
    }
    return this;
  },

  packageJson: function checkIfPackageJson(source) {
    if (typeof source === 'undefined') {
      throw new Error('"source" param is required.', 'check-if.js');
    }
    if (source instanceof PackageJson) {
      this.configJsonObj = source;
    } else if (typeof source === 'string') {
      this.configJsonObj = configJsonFactory.createConfigJson('npm', source);
    } else {
      throw new TypeError('Unknown source: ' + source, 'check-if.js');
    }
    return this;
  },

  passesTheFilter: function (filterBy) {

    var keywords = null;

    if (typeof this.configJsonObj === 'undefined') {
      throw new Error('this.configJsonObj is not defined', 'check-if.js');
    }

    if (typeof filterBy === 'undefined' || typeof filterBy.keyword === 'undefined') {
      return true;
    }

    if (typeof filterBy.keyword === 'string') {
      keywords = [filterBy.keyword];
    } else {
      keywords = filterBy.keyword;
    }
    for (var i = 0, length = keywords.length; i < length; i++) {
      if(this.configJsonObj.has.not.keyword(keywords[i])){
        return false;
      }
    }

    return true;
  },

  doesntPassTheFilter: function (filterBy) {
    return !this.passesTheFilter(filterBy);
  }

};

module.exports = function () {
  return new CheckIf();
};
<commit_msg>Throw Error instead of RangeError<commit_after>/* jshint node: true */
'use strict';

var BowerJson = require('../json/bower-json.js'),
    PackageJson = require('../json/package-json.js'),
    configJsonFactory = require('../json/config-json-factory.js');

function CheckIf() {}

CheckIf.prototype = {

  configJson: function (source, configManager) {
    if (configManager === 'bower') {
      this.bowerJson(source);
    } else if (configManager === 'npm') {
      this.packageJson(source);
    } else {
      throw new TypeError('Unknown configManager: ' + configManager, 'check-if.js');
    }
    return this;
  },

  /**
   * Adds readability to BowerJson filters.
   * If source param is a path, returns a new BowerJson object.
   * @param  {} source [description]
   * @return {BowerJson}        [description]
   */
  bowerJson: function checkIfBowerJson(source) {
    if (typeof source === 'undefined') {
      throw new Error('"source" param is required.', 'check-if.js');
    }
    if (source instanceof BowerJson) {
      this.configJsonObj = source;
    } else if (typeof source === 'string') {
      this.configJsonObj = configJsonFactory.createConfigJson('bower', source);
    } else {
      throw new TypeError('Unknown source: ' + source, 'check-if.js');
    }
    return this;
  },

  packageJson: function checkIfPackageJson(source) {
    if (typeof source === 'undefined') {
      throw new Error('"source" param is required.', 'check-if.js');
    }
    if (source instanceof PackageJson) {
      this.configJsonObj = source;
    } else if (typeof source === 'string') {
      this.configJsonObj = configJsonFactory.createConfigJson('npm', source);
    } else {
      throw new Error('Unknown source: ' + source, 'check-if.js');
    }
    return this;
  },

  passesTheFilter: function (filterBy) {

    var keywords = null;

    if (typeof this.configJsonObj === 'undefined') {
      throw new Error('this.configJsonObj is not defined', 'check-if.js');
    }

    if (typeof filterBy === 'undefined' || typeof filterBy.keyword === 'undefined') {
      return true;
    }

    if (typeof filterBy.keyword === 'string') {
      keywords = [filterBy.keyword];
    } else {
      keywords = filterBy.keyword;
    }
    for (var i = 0, length = keywords.length; i < length; i++) {
      if(this.configJsonObj.has.not.keyword(keywords[i])){
        return false;
      }
    }

    return true;
  },

  doesntPassTheFilter: function (filterBy) {
    return !this.passesTheFilter(filterBy);
  }

};

module.exports = function () {
  return new CheckIf();
};
<|endoftext|>


<commit_before>/**
 * @class SensortagDeamon
 * @date 2014-01-09
 * @author Clotaire Delanchy <clo.delanchy@gmail.com>
 * @requires sensortag
 * @description
 *
 * Deamon to communicate with the SensorTag
 */
'use strict';

// Script requirements
// ********************

var util = require('util');
var async = require('async');
var SensorTag = require('sensortag');
var pkg = require('../package');

/*
 * Constructor of the Sensortag Deamon
 */
function SensortagDeamon() {
	var self = this;
	console.log('[SensorTag] deamon created');
}

/**
 * Action the deamon is doing:
 * - discovering the closest SensorTag,
 * - enable accelerometer, gyroscope, temperature and buttons features,
 * - read this values once,
 * - trigger alerts if specific events arrive (fall for instance).
 * @return none
 */
SensortagDeamon.prototype.start = function() {

	var self = this;
	console.log('[SensorTag] deamon started!');

	SensorTag.discover(function(sensorTag) {

		sensorTag.on('disconnect', function() {
			console.log('[SensorTag] disconnected!');
		});

		async.series([
			function(callback) {
				console.log('[SensorTag] connect');
				sensorTag.connect(callback);
			},
			function(callback) {
				console.log('[SensorTag] discoverServicesAndCharacteristics');
	        	sensorTag.discoverServicesAndCharacteristics(callback);
	      	},
	      	function(callback) {
	        	console.log('[SensorTag] enableIrTemperature');
	        	sensorTag.enableIrTemperature(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] enableAccelerometer');
	      		sensorTag.enableAccelerometer(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] enableGyroscope');
	      		sensorTag.enableGyroscope(callback);
	      	},
	      	function(callback) {
	        	setTimeout(callback, 1000);
	      	},
	      	function(callback) {
	        	console.log('[SensorTag] readIrTemperature');
	        	sensorTag.readIrTemperature(function(objectTemperature, ambientTemperature) {
	          		//console.log('\tobject temperature = %d °C', objectTemperature.toFixed(1));
	          		console.log('\tambient temperature = %d °C', ambientTemperature.toFixed(1));

		          	callback();
	        	});

	        	sensorTag.on('irTemperatureChange', function(objectTemperature, ambientTemperature) {
	        		//console.log('\tambient temperature = %d °C', ambientTemperature.toFixed(1));
	        	});

	        	sensorTag.notifyIrTemperature(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] readAccelerometer');
	      		sensorTag.readAccelerometer(function(x, y, z) {
	      			console.log('X : ' + x + 'g');
	      			console.log('Y : ' + y + 'g');
	      			console.log('Z : ' + z + 'g');

	      			callback();
	      		});

	      		sensorTag.on('accelerometerChange', function(x, y, z) {
	      			//console.log(self.norme(x, y, z));
	      		});

	      		sensorTag.notifyAccelerometer(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] readGyroscope');
	      		sensorTag.readGyroscope(function(x, y, z) {
	      			console.log('X : ' + x + '°/s');
	      			console.log('Y : ' + y + '°/s');
	      			console.log('Z : ' + z + '°/s');
	      		});

	      		sensorTag.on('gyroscopeChange', function(x, y, z) {
	      			// console.log('X : ' + x + '°/s');
	      			// console.log('Y : ' + y + '°/s');
	      			// console.log('Z : ' + z + '°/s');

	      			//console.log('Gyro : ' + self.norme(x, y, z));
	      			self.fallDetection(x, y, z);
	      		});

	      		sensorTag.notifyGyroscope(callback);
	      	},
	      	function(callback) {
	      		sensorTag.on('simpleKeyChange', function(left, right) {
	      			if(left && right) {
	      				console.log('[SensorTag] Dos botones!');
	      			} else if(left) {
	      				console.log('[SensorTag] Boton izquierdo');
	      			} else if(right) {
	      				console.log('[SensorTag] Boton derecho');
	      			}
	      		});

	      		sensorTag.notifySimpleKey(callback);
	      	}
	      	// function(callback) {
        // 		console.log('disconnect');
        // 		sensorTag.disconnect(callback);
      		// }
	    ]);
	});
};

/**
 * Calculate the norm of the vector (x, y ,z) given in parameter
 * @param x - value for the x axis
 * @param y - value for the y axis
 * @param z - value for the z axis
 * @return norm of the vector
 */
SensortagDeamon.prototype.norme = function(x, y, z) {
	var norme = Math.sqrt(x*x + y*y + z*z);
	return norme;
};

/**
 * Algorithm to detect if a fall appeared. It uses the norm of the vector and a threshold.
 * @param x - value for the x axis
 * @param y - value for the y axis
 * @param z - value for the z axis
 * @param threshold - value of the threshold
 */
SensortagDeamon.prototype.fallDetection = function(x, y, z, threshold) {
	var threshold = threshold || 250;
	var self = this;
	var norme = self.norme(x, y, z);

	if(norme >= threshold) {
		console.log('[SensorTag] Alerte ! Mémé par terre !');
	}
};

module.exports = SensortagDeamon;
<commit_msg>add communication with the server when an alert is detected<commit_after>/**
 * @class SensortagDeamon
 * @date 2014-01-09
 * @author Clotaire Delanchy <clo.delanchy@gmail.com>
 * @requires sensortag
 * @description
 *
 * Deamon to communicate with the SensorTag
 */
'use strict';

// Script requirements
// ********************

var util = require('util');
var async = require('async');
var SensorTag = require('sensortag');
var pkg = require('../package');

/*
 * Constructor of the Sensortag Deamon
 */
function SensortagDeamon(server) {
	var self = this;
	this._server = server;
	console.log('[SensorTag] deamon created');
}

/**
 * Action the deamon is doing:
 * - discovering the closest SensorTag,
 * - enable accelerometer, gyroscope, temperature and buttons features,
 * - read this values once,
 * - trigger alerts if specific events arrive (fall for instance).
 * @return none
 */
SensortagDeamon.prototype.start = function() {

	var self = this;
	console.log('[SensorTag] deamon started!');

	SensorTag.discover(function(sensorTag) {

		sensorTag.on('disconnect', function() {
			console.log('[SensorTag] disconnected!');
		});

		async.series([
			function(callback) {
				console.log('[SensorTag] connect');
				sensorTag.connect(callback);
			},
			function(callback) {
				console.log('[SensorTag] discoverServicesAndCharacteristics');
	        	sensorTag.discoverServicesAndCharacteristics(callback);
	      	},
	      	function(callback) {
	        	console.log('[SensorTag] enableIrTemperature');
	        	sensorTag.enableIrTemperature(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] enableAccelerometer');
	      		sensorTag.enableAccelerometer(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] enableGyroscope');
	      		sensorTag.enableGyroscope(callback);
	      	},
	      	function(callback) {
	        	setTimeout(callback, 1000);
	      	},
	      	function(callback) {
	        	console.log('[SensorTag] readIrTemperature');
	        	sensorTag.readIrTemperature(function(objectTemperature, ambientTemperature) {
	          		//console.log('\tobject temperature = %d °C', objectTemperature.toFixed(1));
	          		console.log('\tambient temperature = %d °C', ambientTemperature.toFixed(1));

		          	callback();
	        	});

	        	sensorTag.on('irTemperatureChange', function(objectTemperature, ambientTemperature) {
	        		if(ambientTemperature.toFixed(1) <= 10 || ambientTemperature.toFixed(1) >= 30) {
	        			self.sendTempAlert(ambientTemperature.toFixed(1));
	        		}
	        	});

	        	sensorTag.notifyIrTemperature(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] readAccelerometer');
	      		sensorTag.readAccelerometer(function(x, y, z) {
	      			console.log('X : ' + x + 'g');
	      			console.log('Y : ' + y + 'g');
	      			console.log('Z : ' + z + 'g');

	      			callback();
	      		});

	      		sensorTag.on('accelerometerChange', function(x, y, z) {
	      			//console.log(self.norme(x, y, z));
	      		});

	      		sensorTag.notifyAccelerometer(callback);
	      	},
	      	function(callback) {
	      		console.log('[SensorTag] readGyroscope');
	      		sensorTag.readGyroscope(function(x, y, z) {
	      			console.log('X : ' + x + '°/s');
	      			console.log('Y : ' + y + '°/s');
	      			console.log('Z : ' + z + '°/s');
	      		});

	      		sensorTag.on('gyroscopeChange', function(x, y, z) {
	      			// console.log('X : ' + x + '°/s');
	      			// console.log('Y : ' + y + '°/s');
	      			// console.log('Z : ' + z + '°/s');

	      			//console.log('Gyro : ' + self.norme(x, y, z));
	      			self.fallDetection(x, y, z);
	      		});

	      		sensorTag.notifyGyroscope(callback);
	      	},
	      	function(callback) {
	      		sensorTag.on('simpleKeyChange', function(left, right) {
	      			if(left && right) {
	      				console.log('[SensorTag] Dos botones!');
	      			} else if(left) {
	      				console.log('[SensorTag] Boton izquierdo');
	      			} else if(right) {
	      				console.log('[SensorTag] Boton derecho');
	      			}
	      			self.sendKeyAlert(left, right);
	      		});

	      		sensorTag.notifySimpleKey(callback);
	      	}
	      	// function(callback) {
        // 		console.log('disconnect');
        // 		sensorTag.disconnect(callback);
      		// }
	    ]);
	});
};

/**
 * Calculate the norm of the vector (x, y ,z) given in parameter
 * @param x - value for the x axis
 * @param y - value for the y axis
 * @param z - value for the z axis
 * @return norm of the vector
 */
SensortagDeamon.prototype.norme = function(x, y, z) {
	var norme = Math.sqrt(x*x + y*y + z*z);
	return norme;
};

/**
 * Algorithm to detect if a fall appeared. It uses the norm of the vector and a threshold.
 * @param x - value for the x axis
 * @param y - value for the y axis
 * @param z - value for the z axis
 * @param threshold - value of the threshold
 */
SensortagDeamon.prototype.fallDetection = function(x, y, z, threshold) {
	var threshold = threshold || 250;
	var self = this;
	var norme = self.norme(x, y, z);

	if(norme >= threshold) {
		console.log('[SensorTag] Alerte ! Mémé par terre !');
		self.sendFallAlert(x, y, z, threshold, norme);
	}
};

SensortagDeamon.prototype.sendFallAlert = function(x, y ,z, threshold, norme) {
	var self = this;
	var alert = {
		type: 'FallAlert',
		data: {
			x: x,
			y: y,
			z: z,
			threshold: threshold,
			norme: norme
		}
	};
	this._server.notifyFallAlert(alert);
};

SensortagDeamon.prototype.sendDisconnectAlert = function() {

};

SensortagDeamon.prototype.sendTempAlert = function(temperature) {
	var self = this;
	var alert = {
		type: 'TempAlert',
		data: {
			temp: temperature
		}
	};
	this._server.notifyTempAlert(alert);
};

SensortagDeamon.prototype.sendKeyAlert = function(left, right) {
	var self = this;
	var alert = {
		type: 'KeyAlert',
		data: {
			left: left,
			right: right
		}
	};
	this._server.notifyKeyAlert(alert);
};

module.exports = SensortagDeamon;
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var fs              = require('fs'),
        path            = require('path'),

        Util            = require('../util'),
        tryRequire      = require('./tryRequire'),
        beautify        = tryRequire('js-beautify'),

        DIR             = '../../',
        HOME_WIN        = process.env.HOMEPATH,
        HOME_UNIX       = process.env.HOME,
        HOME            = (HOME_UNIX || HOME_WIN) + '/',

        EXT             = ['js', 'css', 'html'],
        ERROR_MSG       = 'File type "{{ ext }}" not supported.',
        ERROR_MSG_INST  = 'Beautify not installed',
        ConfigPath      = DIR   + 'json/beautify.json',
        ConfigHome      = HOME  + '.beautify.json',

        config          =
            tryRequire(ConfigHome) ||
            tryRequire(ConfigPath, {log: true}) || {};

    module.exports  = function(name, callback) {
        var ext     = path
                .extname(name)
                .slice(1),

            is      = ~EXT.indexOf(ext);

        if (!beautify)
            callback(Error(ERROR_MSG_INST));
        else if (!is)
            callback(Error(Util.render(ERROR_MSG, {
                ext : ext
            })));
        else
            fs.readFile(name, 'utf8', function(error, data) {
                var result;

                if (!error)
                    error = Util.exec.try(function() {
                        result = beautify[ext](data, config);
                    });

                callback(error, result);
            });
    };

})();
<commit_msg>feature(beautify) / -> path.sep<commit_after>(function() {
    'use strict';

    var fs              = require('fs'),
        path            = require('path'),

        Util            = require('../util'),
        tryRequire      = require('./tryRequire'),
        beautify        = tryRequire('js-beautify'),

        DIR             = '../../',
        HOME_WIN        = process.env.HOMEPATH,
        HOME_UNIX       = process.env.HOME,
        HOME            = (HOME_UNIX || HOME_WIN) + path.sep,

        EXT             = ['js', 'css', 'html'],
        ERROR_MSG       = 'File type "{{ ext }}" not supported.',
        ERROR_MSG_INST  = 'Beautify not installed',
        ConfigPath      = DIR   + 'json/beautify.json',
        ConfigHome      = HOME  + '.beautify.json',

        config          =
            tryRequire(ConfigHome) ||
            tryRequire(ConfigPath, {log: true}) || {};

    module.exports  = function(name, callback) {
        var ext     = path
                .extname(name)
                .slice(1),

            is      = ~EXT.indexOf(ext);

        if (!beautify)
            callback(Error(ERROR_MSG_INST));
        else if (!is)
            callback(Error(Util.render(ERROR_MSG, {
                ext : ext
            })));
        else
            fs.readFile(name, 'utf8', function(error, data) {
                var result;

                if (!error)
                    error = Util.exec.try(function() {
                        result = beautify[ext](data, config);
                    });

                callback(error, result);
            });
    };

})();
<|endoftext|>