<commit_before>/**
 * sails-generate-backend
 *
 * Usage:
 * + Automatically called by `sails new`
 *
 * @type {Object}
 */

module.exports = {

  templatesDirectory: require('path').resolve(__dirname,'../templates'),

  before: require('./before'),

  targets: {

    '.': ['views'],
    './api/controllers': { folder: {}},
    './api/models': { folder: {}},
    './api/policies': { folder: {}},
    './api/services': { folder: {}},
    './api/responses': { folder: {}},

    './api/controllers/.gitkeep': { copy: '.gitkeep'},
    './api/models/.gitkeep': { copy: '.gitkeep'},
    './api/services/.gitkeep': { copy: '.gitkeep'},
    './config/connections.js': { copy: 'config/connections.js' },
    './config/models.js': { copy: 'config/models.js' },
    './config/blueprints.js': { copy: 'config/blueprints.js' },
    './config/bootstrap.js': { copy: 'config/bootstrap.js' },
    './config/cors.js': { copy: 'config/cors.js' },
    './config/csrf.js': { copy: 'config/csrf.js' },
    './config/http.js': { copy: 'config/http.js' },
    './config/globals.js': { copy: 'config/globals.js' },
    './config/i18n.js': { copy: 'config/i18n.js' },
    './config/local.js': { copy: 'config/local.js' },
    './config/log.js': { copy: 'config/log.js' },
    './config/policies.js': { copy: 'config/policies.js' },
    './config/routes.js': { copy: 'config/routes.js' },
    './config/sockets.js': { copy: 'config/sockets.js' },

    './config/session.js': { template: 'config/session.js' },
    './config/views.js': { template: 'config/views.js' },

    './config/locales/de.json': { copy: 'config/locales/de.json' },
    './config/locales/en.json': { copy: 'config/locales/en.json' },
    './config/locales/es.json': { copy: 'config/locales/es.json' },
    './config/locales/fr.json': { copy: 'config/locales/fr.json' },
    './config/locales/_README.md': { copy: 'config/locales/_README.md' },

    './config/env/production.js': { copy: 'config/env/production.js' },
    './config/env/development.js': { copy: 'config/env/development.js' },

    './api/policies/sessionAuth.js': { copy: 'api/policies/sessionAuth.js' },

    './api/responses/badRequest.js': { copy: 'api/responses/badRequest.js' },
    './api/responses/forbidden.js': { copy: 'api/responses/forbidden.js' },
    './api/responses/notFound.js': { copy: 'api/responses/notFound.js' },
    './api/responses/serverError.js': { copy: 'api/responses/serverError.js' },
    './api/responses/ok.js': { copy: 'api/responses/ok.js' },

    // Excluding `res.negotiate()` from the generated files for now,
    // since it's best if its definition is consistent between projects.
    // It can still be overridden by creating api/responses/negotiate.js.
    // './api/responses/negotiate.js': { copy: 'api/responses/negotiate.js' },

  }
};

<commit_msg>Actually copy "created.js" template!<commit_after>/**
 * sails-generate-backend
 *
 * Usage:
 * + Automatically called by `sails new`
 *
 * @type {Object}
 */

module.exports = {

  templatesDirectory: require('path').resolve(__dirname,'../templates'),

  before: require('./before'),

  targets: {

    '.': ['views'],
    './api/controllers': { folder: {}},
    './api/models': { folder: {}},
    './api/policies': { folder: {}},
    './api/services': { folder: {}},
    './api/responses': { folder: {}},

    './api/controllers/.gitkeep': { copy: '.gitkeep'},
    './api/models/.gitkeep': { copy: '.gitkeep'},
    './api/services/.gitkeep': { copy: '.gitkeep'},
    './config/connections.js': { copy: 'config/connections.js' },
    './config/models.js': { copy: 'config/models.js' },
    './config/blueprints.js': { copy: 'config/blueprints.js' },
    './config/bootstrap.js': { copy: 'config/bootstrap.js' },
    './config/cors.js': { copy: 'config/cors.js' },
    './config/csrf.js': { copy: 'config/csrf.js' },
    './config/http.js': { copy: 'config/http.js' },
    './config/globals.js': { copy: 'config/globals.js' },
    './config/i18n.js': { copy: 'config/i18n.js' },
    './config/local.js': { copy: 'config/local.js' },
    './config/log.js': { copy: 'config/log.js' },
    './config/policies.js': { copy: 'config/policies.js' },
    './config/routes.js': { copy: 'config/routes.js' },
    './config/sockets.js': { copy: 'config/sockets.js' },

    './config/session.js': { template: 'config/session.js' },
    './config/views.js': { template: 'config/views.js' },

    './config/locales/de.json': { copy: 'config/locales/de.json' },
    './config/locales/en.json': { copy: 'config/locales/en.json' },
    './config/locales/es.json': { copy: 'config/locales/es.json' },
    './config/locales/fr.json': { copy: 'config/locales/fr.json' },
    './config/locales/_README.md': { copy: 'config/locales/_README.md' },

    './config/env/production.js': { copy: 'config/env/production.js' },
    './config/env/development.js': { copy: 'config/env/development.js' },

    './api/policies/sessionAuth.js': { copy: 'api/policies/sessionAuth.js' },

    './api/responses/badRequest.js': { copy: 'api/responses/badRequest.js' },
    './api/responses/forbidden.js': { copy: 'api/responses/forbidden.js' },
    './api/responses/notFound.js': { copy: 'api/responses/notFound.js' },
    './api/responses/serverError.js': { copy: 'api/responses/serverError.js' },
    './api/responses/ok.js': { copy: 'api/responses/ok.js' },
    './api/responses/created.js': { copy: 'api/responses/created.js' }

    // Excluding `res.negotiate()` from the generated files for now,
    // since it's best if its definition is consistent between projects.
    // It can still be overridden by creating api/responses/negotiate.js.
    // './api/responses/negotiate.js': { copy: 'api/responses/negotiate.js' },

  }
};

<|endoftext|>


<commit_before>const CuvvaError = require('./cuvva-error');

module.exports.CuvvaError = CuvvaError;

const errorLevels = {
	debug: 0,
	info: 1,
	warn: 2,
	error: 3,
	fatal: 4,
};

const config = {
	handlers: {},
	minLogLevel: null,
	service: '',
};

// default config
for (var level in errorLevels)
	config.handlers[level] = defaultHandler;

config.minLogLevel = errorLevels.info;

function defaultHandler(level, error) {
	const showStack = ['fatal', 'error'].includes(level);

	const formattedError = {
		...error,
		stack: showStack ? error.stack : void 0,
		reasons: error.reasons && error.reasons.map(r => ({ ...r, stack: showStack ? r.stack : void 0 })),
	}

	const message = JSON.stringify({
		'@level': level,
		'@timestamp': new Date().toISOString(),
		'git_commit': process.env.GIT_COMMIT || 'dev',
		'service': config.service || void 0,
		...formattedError,
	});

	if (level === 'fatal') {
		process.stderr.write(message + '\n');
	} else {
		process.stdout.write(message + '\n');
	}
}

function handleError(level, error) {
	if (errorLevels[level] < config.minLogLevel)
		return;

	defaultHandler(level, error);

	config.handlers[level](level, error);
}

module.exports.setHandler = function (level, handler) {
	if (handler === void 0 && typeof level === 'function') {
		handler = level;
		level = null;
	}

	if (typeof handler !== 'function')
		throw new Error('Handler is not a function');

	if (level) {
		config.handlers[level] = handler;
	} else {
		for (var prop in config.handlers)
			config.handlers[prop] = handler;
	}
};

module.exports.setMinLogLevel = function (level) {
	config.minLogLevel = errorLevels[level];
};

module.exports.setService = function (service) {
	config.service = service;
};

function logger(level) {
	return function (code, reasons, meta) {
		if (code instanceof CuvvaError) {
			handleError(level, code);
			return code;
		}

		const error = new CuvvaError(code, reasons, meta);
		handleError(level, error);
		return error;
	};
}

module.exports.debug = logger('debug');
module.exports.info = logger('info');
module.exports.warn = logger('warn');
module.exports.error = logger('error');
module.exports.fatal = logger('fatal');
<commit_msg>simplify default config<commit_after>const CuvvaError = require('./cuvva-error');

module.exports.CuvvaError = CuvvaError;

const errorLevels = {
	debug: 0,
	info: 1,
	warn: 2,
	error: 3,
	fatal: 4,
};

const config = {
	handlers: {},
	minLogLevel: errorLevels.info,
	service: 'unknown',
};

// default config
for (var level in errorLevels)
	config.handlers[level] = defaultHandler;

function defaultHandler(level, error) {
	const showStack = ['fatal', 'error'].includes(level);

	const formattedError = {
		...error,
		stack: showStack ? error.stack : void 0,
		reasons: error.reasons && error.reasons.map(r => ({ ...r, stack: showStack ? r.stack : void 0 })),
	}

	const message = JSON.stringify({
		'@level': level,
		'@timestamp': new Date().toISOString(),
		'git_commit': process.env.GIT_COMMIT || 'dev',
		'service': config.service || void 0,
		...formattedError,
	});

	if (level === 'fatal') {
		process.stderr.write(message + '\n');
	} else {
		process.stdout.write(message + '\n');
	}
}

function handleError(level, error) {
	if (errorLevels[level] < config.minLogLevel)
		return;

	defaultHandler(level, error);

	config.handlers[level](level, error);
}

module.exports.setHandler = function (level, handler) {
	if (handler === void 0 && typeof level === 'function') {
		handler = level;
		level = null;
	}

	if (typeof handler !== 'function')
		throw new Error('Handler is not a function');

	if (level) {
		config.handlers[level] = handler;
	} else {
		for (var prop in config.handlers)
			config.handlers[prop] = handler;
	}
};

module.exports.setMinLogLevel = function (level) {
	config.minLogLevel = errorLevels[level];
};

module.exports.setService = function (service) {
	config.service = service;
};

function logger(level) {
	return function (code, reasons, meta) {
		if (code instanceof CuvvaError) {
			handleError(level, code);
			return code;
		}

		const error = new CuvvaError(code, reasons, meta);
		handleError(level, error);
		return error;
	};
}

module.exports.debug = logger('debug');
module.exports.info = logger('info');
module.exports.warn = logger('warn');
module.exports.error = logger('error');
module.exports.fatal = logger('fatal');
<|endoftext|>


<commit_before>var async = require('async');

function captainHook(schema) {

  // Pre-Save Setup
  schema.pre('save', function (next) {
    var self = this;
    this._wasNew = this.isNew;
    if (this.isNew) {
      this.runPreCreate(self, function(){
        next();
      })
    } else {
      this.runPreUpdate(self, function(){
        next();
      })
    }
  })

  // Post-Save Setup
  schema.post('save', function () {
    var self = this;
    if (this._wasNew) {
      this.runPostCreate(self);
    } else {
      this.runPostUpdate(self);
    }
  })

  // Pre-Create Methods
  schema.preCreateMethods = []

  schema.preCreate = function(fn){
    schema.preCreateMethods.push(fn);
  }

  schema.methods.runPreCreate = function(self, callback){
    async.eachSeries(schema.preCreateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        callback();
    });
  }

  // Pre-Update Methods
  schema.preUpdateMethods = []

  schema.preUpdate = function(fn){
    schema.preUpdateMethods.push(fn);
  }

  schema.methods.runPreUpdate = function(self, callback){
    async.eachSeries(schema.preUpdateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        callback();
    });
  }

  // Post-Create Methods
  schema.postCreateMethods = []

  schema.postCreate = function(fn){
    schema.postCreateMethods.push(fn);
  }

  schema.methods.runPostCreate = function(self, callback){
    async.eachSeries(schema.postCreateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        if (err) {
          console.log(err);
        }
    });
  }

  // Post-Update Methods
  schema.postUpdateMethods = []

  schema.postUpdate = function(fn){
    schema.postUpdateMethods.push(fn);
  }

  schema.methods.runPostUpdate = function(self, callback){
    async.eachSeries(schema.postUpdateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        if (err) {
          console.log(err);
        }
    });
  }

}

module.exports = captainHook;
<commit_msg>Fix lint issues<commit_after>var async = require('async');

function captainHook(schema) {

  // Pre-Save Setup
  schema.pre('save', function (next) {
    var self = this;
    this._wasNew = this.isNew;
    if (this.isNew) {
      this.runPreCreate(self, function(){
        next();
      });
    } else {
      this.runPreUpdate(self, function(){
        next();
      });
    }
  });

  // Post-Save Setup
  schema.post('save', function () {
    var self = this;
    if (this._wasNew) {
      this.runPostCreate(self);
    } else {
      this.runPostUpdate(self);
    }
  });

  // Pre-Create Methods
  schema.preCreateMethods = [];

  schema.preCreate = function(fn){
    schema.preCreateMethods.push(fn);
  };

  schema.methods.runPreCreate = function(self, callback){
    async.eachSeries(schema.preCreateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        if (err) throw err;
        callback();
    });
  };

  // Pre-Update Methods
  schema.preUpdateMethods = [];

  schema.preUpdate = function(fn){
    schema.preUpdateMethods.push(fn);
  };

  schema.methods.runPreUpdate = function(self, callback){
    async.eachSeries(schema.preUpdateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        if (err) throw err;
        callback();
    });
  };

  // Post-Create Methods
  schema.postCreateMethods = [];

  schema.postCreate = function(fn){
    schema.postCreateMethods.push(fn);
  };

  schema.methods.runPostCreate = function(self){
    async.eachSeries(schema.postCreateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        if (err) throw err;
    });
  };

  // Post-Update Methods
  schema.postUpdateMethods = [];

  schema.postUpdate = function(fn){
    schema.postUpdateMethods.push(fn);
  };

  schema.methods.runPostUpdate = function(self){
    async.eachSeries(schema.postUpdateMethods,
      function(fn, cb) {
        fn(self, cb);
      }, function(err){
        if (err) throw err;
    });
  };

}

module.exports = captainHook;
<|endoftext|>


<commit_before>"use strict";

var _ = require('lodash');
var path = require('path');
var Schema = require('node-verifier-schema');
var loader = require('node-verifier-schema/load');

var defaultsOptions = {
	cwd: process.cwd(),

	preparePath: function (filepath) {
		return path.join(this.cwd, filepath);
	},

	prepareSchema: function (schema, options) {
		var _rawSchema = schema;
		if (_.isString(schema)) {
			if (/\.(yaml|yml)$/.test(schema)) {
				schema = options.preparePath(schema);
				schema = loader(schema);
			} else {
				schema = Schema.get(schema);
			}
		} else if (_.isFunction(schema)) {
			schema = new Schema();
			_rawSchema(schema);
		}

		if (!(schema instanceof Schema)) {
			throw new Error('must be Schema instance. ' + _rawSchema + ' given');
		}

		return schema;
	}
};

var expressVerifier = function (globalOptions) {
	var verifier = function (object, options) {
		options = _.extend({}, defaultsOptions, globalOptions, options);

		var keys = _.keys(verifier.objects);

		if (!_.isPlainObject(object)) {
			object = options.prepareSchema(object, options).fields;
		}

		var verifiers = [];
		_.each(keys, function (key) {
			if (_.has(object, key)) {
				verifiers.push({
					name: key,
					verify: verifier.objects[key](object[key], options)
				});
			}
		});

		if (!verifiers.length) {
			throw new Error('invalid parameters for verify');
		}

		var middleware = function (req, res, next) {
			Schema.utils.iterate.array(middleware.verifiers, function (obj, index, done) {
				obj.verify(req, res, function (err) {
					if (err instanceof Schema.ValidationError) {
						err.object = object.name;
					}

					done(err);
				});
			}, next);
		};

		middleware.verifiers = verifiers;

		return middleware;
	};

	verifier.objects = {
		params: function (schema, options) {
			schema = options.prepareSchema(schema, options, 'params');
			var verifier = schema.verifier(options);

			var verf = function (req, res, next) {
				verifier.verify(req.params, next);
			};

			verf.schema = schema;
			return verf;
		},
		query: function (schema, options) {
			schema = options.prepareSchema(schema, options, 'query');
			var verifier = schema.verifier(options);

			var verf = function (req, res, next) {
				verifier.verify(req.query, next);
			};

			verf.schema = schema;
			return verf;
		},
		body: function (schema, options) {
			schema = options.prepareSchema(schema, options, 'body');
			var verifier = schema.verifier(options);

			var verf = function (req, res, next) {
				verifier.verify(req.body, next);
			};

			verf.schema = schema;
			return verf;
		}
	};

	return verifier;
};

expressVerifier.Verifier = Schema.Verifier;

module.exports = expressVerifier;
<commit_msg>update logic. add separated methods for query,params,body,header<commit_after>"use strict";

var _ = require('lodash');
var path = require('path');
var Schema = require('node-verifier-schema');
var loader = require('node-verifier-schema/load');

var defaultsOptions = {
	cwd: process.cwd(),

	preparePath: function (filepath) {
		return path.join(this.cwd, filepath);
	},

	prepareSchema: function (schema, options) {
		var _rawSchema = schema;
		if (_.isString(schema)) {
			if (/\.(yaml|yml)$/.test(schema)) {
				schema = options.preparePath(schema);
				schema = loader(schema);
			} else {
				schema = Schema.get(schema);
			}
		} else if (_.isFunction(schema)) {
			schema = new Schema();
			_rawSchema(schema);
		}

		if (!(schema instanceof Schema)) {
			throw new Error('must be Schema instance. ' + _rawSchema + ' given');
		}

		return schema;
	}
};

var verifierObject = function (name) {
	return function (schema, options) {
		schema = options.prepareSchema(schema, options, name);
		var verifier = schema.verifier(options);

		var verf = function (req, res, next) {
			verifier.verify(req[name], next);
		};

		verf.schema = schema;
		return verf;
	};
};

var expressVerifier = function (globalOptions) {
	var verifier = function (object, options) {
		options = _.extend({}, defaultsOptions, globalOptions, options);

		var keys = _.keys(verifier.objects);

		if (!_.isPlainObject(object)) {
			object = options.prepareSchema(object, options).fields;
		}

		var verifiers = [];
		_.each(keys, function (key) {
			if (_.has(object, key)) {
				verifiers.push({
					name: key,
					verify: verifier.objects[key](object[key], options)
				});
			}
		});

		if (!verifiers.length) {
			throw new Error('invalid parameters for verify');
		}

		var middleware = function (req, res, next) {
			Schema.utils.iterate.array(middleware.verifiers, function (obj, index, done) {
				obj.verify(req, res, function (err) {
					if (err instanceof Schema.ValidationError) {
						err.object = obj.name;
					}

					done(err);
				});
			}, next);
		};

		middleware.verifiers = verifiers;

		return middleware;
	};

	verifier.objects = {
		body: verifierObject('body'),
		query: verifierObject('query'),
		params: verifierObject('params'),
		headers: verifierObject('headers')
	};

	_.each(verifier.objects, function (v, k) {
		verifier[k] = function (object, options) {
			var obj = {};
			obj[k] = object;
			return verifier(obj, options);
		};
	});

	return verifier;
};

expressVerifier.Verifier = Schema.Verifier;

module.exports = expressVerifier;
<|endoftext|>


<commit_before>// Module dependencies
var koa = require('koa'),
	co = require('co'),
	path = require('path'),
	commons = require('koa-common'),
	thunkify = require('thunkify'),
	glob = thunkify(require("glob")),
	bodyParser = require('koa-bodyparser'),
	config = require('./config'),
	send = require('koa-send');

exports = module.exports = Gaia;

function Gaia(appDir) {
	if (!(this instanceof Gaia)) return new Gaia(appDir);
	if (!appDir) {
		throw new Error("appDir can't be blank");
	}
	this._appDir = appDir;
	config._initialize(appDir);
	this.config = config;
	this._app = koa();
}

Gaia.prototype.initLog = function() {
	var log = require('./log');
	this.log = log.gaia;
	GLOBAL.Log = log.app;
}

Gaia.prototype.initMiddleware = function *() {
	if (config.application.session) {
		var session = require('koa-sess');
		this._app.keys = config.application.session.keys || ['default-session-keys'];
		this._app.use(session());
	}

	this._app.use(bodyParser());
	if (config.authentification) {
		var auth = config.authentification;

		var passport = require('koa-passport');
		yield auth.init(passport, this.database);

		this._app.use(passport.initialize());
		this._app.use(passport.session());
		GLOBAL.Passport = this.passport = passport;
	}

	if (config.application.views) {
		var views = require('koa-render'),
			viewDir = config.application.views.dir || path.resolve(this._appDir, 'views');
			options = config.application.views.options;

		this._app.use(views(viewDir, options));
	}

	this._app.use(commons.favicon());
	this._app.use(commons.logger());
	this._app.use(commons.responseTime());
	this._app.use(commons.compress());

	//public
	var publicDir = "public",
		publicPath = "/public";

	if (config.application.public) {
		if (config.application.public.publicDir) publicDir = config.application.public.publicDir;
		if (config.application.public.publicPath) publicPath = config.application.public.publicPath
	}

	// this._app.use(function *(next){
	// 	console.log(this.path);
	// 	if (this.path.indexOf('/public') == 0) return yield next;
	// 	yield send(this, this.path, { root: path.resolve(this._appDir, 'public')});
	// })
};

Gaia.prototype.initDatabase = function *() {
	var database = require('./database');
	this.database = database;
	GLOBAL.Database = database;
	yield database.init(this);
	this._app.use(database.injectDatabase());
}

Gaia.prototype.initRouter = function *() {
	var router = yield require('./router')(this);
}

Gaia.prototype.start = function() {
	var self = this;
	co(function *() {
		self.initLog();
		self.log.info("Init database");

		//if (self.config.database) {
			yield self.initDatabase();
			self.log.info("Init initMiddlewares");
			yield self.initMiddleware();
		//}

		self.log.info("Init router");
		yield self.initRouter();

		self._app.listen(config.application.port);
    	self.log.info('connected to database and listening on port:', config.application.port);
	})();
}
<commit_msg>correction for static<commit_after>// Module dependencies
var koa = require('koa'),
	co = require('co'),
	path = require('path'),
	commons = require('koa-common'),
	thunkify = require('thunkify'),
	glob = thunkify(require("glob")),
	bodyParser = require('koa-bodyparser'),
	config = require('./config'),
	send = require('koa-send');

exports = module.exports = Gaia;

function Gaia(appDir) {
	if (!(this instanceof Gaia)) return new Gaia(appDir);
	if (!appDir) {
		throw new Error("appDir can't be blank");
	}
	this._appDir = appDir;
	config._initialize(appDir);
	this.config = config;
	this._app = koa();
}

Gaia.prototype.initLog = function() {
	var log = require('./log');
	this.log = log.gaia;
	GLOBAL.Log = log.app;
}

Gaia.prototype.initMiddleware = function *() {
	var self = this;
	if (config.application.session) {
		var session = require('koa-sess');
		this._app.keys = config.application.session.keys || ['default-session-keys'];
		this._app.use(session());
	}

	this._app.use(bodyParser());
	if (config.authentification) {
		var auth = config.authentification;

		var passport = require('koa-passport');
		yield auth.init(passport, this.database);

		this._app.use(passport.initialize());
		this._app.use(passport.session());
		GLOBAL.Passport = this.passport = passport;
	}

	if (config.application.views) {
		var views = require('koa-render'),
			viewDir = config.application.views.dir || path.resolve(this._appDir, 'views');
			options = config.application.views.options;

		this._app.use(views(viewDir, options));
	}

	this._app.use(commons.favicon());
	this._app.use(commons.logger());
	this._app.use(commons.responseTime());
	this._app.use(commons.compress());

	this._app.use(function *(next){
		if (this.path.indexOf('/public') != 0) return yield next;
		this.path = this.path.substring(7);
		yield send(this, this.path, { root: path.resolve(self._appDir, 'public')});
	})
};

Gaia.prototype.initDatabase = function *() {
	var database = require('./database');
	this.database = database;
	GLOBAL.Database = database;
	yield database.init(this);
	this._app.use(database.injectDatabase());
}

Gaia.prototype.initRouter = function *() {
	var router = yield require('./router')(this);
}

Gaia.prototype.start = function() {
	var self = this;
	co(function *() {
		self.initLog();
		self.log.info("Init database");

		//if (self.config.database) {
			yield self.initDatabase();
			self.log.info("Init initMiddlewares");
			yield self.initMiddleware();
		//}

		self.log.info("Init router");
		yield self.initRouter();

		self._app.listen(config.application.port);
    	self.log.info('connected to database and listening on port:', config.application.port);
	})();
}
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var generate = require('./generate');
var path = require('path');
var reportback = require('reportback')();

/**
 * Generate module(s)
 *
 * @param  {Object}   scope [description]
 * @param  {Function} cb    [description]
 * @return {[type]}         [description]
 */
module.exports = function(scope, cb) {
  cb = cb || {};
  cb = reportback.extend(cb, {
    error: cb.error,
    invalid: cb.invalid,
    success: function(output) {
      cb.log.info('ok!');
    },
    notSailsApp: function() {
      cb.log.error('Not a sails app.');
    },
    alreadyExists: function() {
      return cb.error();
    }
  });

  if (!scope.generatorType) {
    return cb.error('Sorry, `scope.generatorType` must be defined.');
  }

  // Use configured module name for this generatorType if applicable.
  var module =
    (scope.modules && scope.modules[scope.generatorType]) ||
    'sails-generate-' + scope.generatorType;

  var Generator;
  var requirePath;
  var requireError;

  function throwIfModuleNotFoundError (e, module) {
    var isModuleNotFoundError = e && e.code === 'MODULE_NOT_FOUND' && e.message.match(new RegExp(module));
    if (!isModuleNotFoundError) {
      cb.log.error('Error in "'+scope.generatorType+'" generator (loaded from '+module+')');
      throw e;
    }
    else return e;
  }

  // Allow `scope.generator` to be specified as an inline generator
  // ... todo ...

  // Try requiring it directly as a path
  // (or using whatever might be in the require path)
  // try {
  //   Generator = require(module);
  // } catch (e) {
  //   requireError = throwIfModuleNotFoundError(e, module);
  // }

  // Try requiring it directly as a path resolved from process.cwd()
  if (!Generator) {
    try {
      requirePath = path.resolve(process.cwd(), module);
      Generator = require(requirePath);
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  // Try requiring the generator from the rootPath
  if (!Generator) {
    try {
      requirePath = path.resolve(scope.rootPath, 'node_modules', module);
      Generator = require(requirePath);
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  // If that doesn't work, try `require()`ing it from console user's cwd
  if (!Generator) {
    try {
      requirePath = path.resolve(process.cwd(), 'node_modules', module);
      Generator = require(requirePath);
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  // Finally, try to load the generator module from sails-generate's dependencies
  if (!Generator) {
    try {
      Generator = require(path.resolve(scope.rootPath || process.cwd(), module));
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  if (!Generator) {
    return cb.log.error("No generator called `" + scope.generatorType + "` found; perhaps you meant `sails generate api " + scope.generatorType + "`?");
  }

  generate(Generator, scope, cb);

};
<commit_msg>Cleanup comments<commit_after>/**
 * Module dependencies
 */

var generate = require('./generate');
var path = require('path');
var reportback = require('reportback')();

/**
 * Generate module(s)
 *
 * @param  {Object}   scope [description]
 * @param  {Function} cb    [description]
 * @return {[type]}         [description]
 */
module.exports = function(scope, cb) {
  cb = cb || {};
  cb = reportback.extend(cb, {
    error: cb.error,
    invalid: cb.invalid,
    success: function(output) {
      cb.log.info('ok!');
    },
    notSailsApp: function() {
      cb.log.error('Not a sails app.');
    },
    alreadyExists: function() {
      return cb.error();
    }
  });

  if (!scope.generatorType) {
    return cb.error('Sorry, `scope.generatorType` must be defined.');
  }

  // Use configured module name for this generatorType if applicable.
  var module =
    (scope.modules && scope.modules[scope.generatorType]) ||
    'sails-generate-' + scope.generatorType;

  var Generator;
  var requirePath;
  var requireError;

  function throwIfModuleNotFoundError (e, module) {
    var isModuleNotFoundError = e && e.code === 'MODULE_NOT_FOUND' && e.message.match(new RegExp(module));
    if (!isModuleNotFoundError) {
      cb.log.error('Error in "'+scope.generatorType+'" generator (loaded from '+module+')');
      throw e;
    }
    else return e;
  }

  // Allow `scope.generator` to be specified as an inline generator
  // ... todo ...

  // Try requiring it directly as a path resolved from process.cwd()
  if (!Generator) {
    try {
      requirePath = path.resolve(process.cwd(), module);
      Generator = require(requirePath);
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  // Try requiring the generator from the rootPath
  if (!Generator) {
    try {
      requirePath = path.resolve(scope.rootPath, 'node_modules', module);
      Generator = require(requirePath);
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  // If that doesn't work, try `require()`ing it from console user's cwd
  if (!Generator) {
    try {
      requirePath = path.resolve(process.cwd(), 'node_modules', module);
      Generator = require(requirePath);
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  // Finally, try to load the generator module from sails-generate's dependencies
  if (!Generator) {
    try {
      Generator = require(path.resolve(scope.rootPath || process.cwd(), module));
    } catch (e) {
      requireError = throwIfModuleNotFoundError(e, module);
    }
  }

  if (!Generator) {
    return cb.log.error("No generator called `" + scope.generatorType + "` found; perhaps you meant `sails generate api " + scope.generatorType + "`?");
  }

  generate(Generator, scope, cb);

};
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////
/*
	module: index.js
	author: Evgeniy Litvinov <raytwitty@gmail.com>
	description: extensions of telegram-node-bot module
*/
//////////////////////////////////////////////////////////

'use strict'

module.exports = (Telegram, tg) => {
	class MultiFormScopeExtension extends Telegram.BaseScopeExtension {
		process(root_form, callback, config) {
			let marked = []
			let answers = {}
			let ignored = ['$name', '$parent', '$last', 'values']

			let checkKeyboard = (keyboard, answer) => {
				for (let value of keyboard) {
					if (value == answer || (Array.isArray(value) && checkKeyboard(value, answer)))
						return true
				}
			}

			let sendMsg = (text, keyboard) => {
				if (text) {
					this.sendMessage(text, {
						disable_web_page_preview: true,
						parse_mode: 'HTML',
						reply_markup: JSON.stringify(keyboard ? {
							one_time_keyboard: true,
							resize_keyboard: true,
							keyboard: keyboard
						} : {remove_keyboard: true})
					})
				}
			}

			let makeMap = form => {
				let last
				Object.forEach(form, (key, value) => {
					if (ignored.indexOf(key) == -1 && isObject(value)) {
						makeMap(value)

						value.$name = key
						value.$parent = form
						value.$last = last
						last = value
					}
				})
			}

			let clearForm = form => {
				marked.remove(form.$name)

				Object.forEach(form, (key, value) => {
					if (ignored.indexOf(key) == -1 && isObject(value))
						clearForm(value)
				})
			}

			let runForm = form => {
				let question
				for (let key in form) {
					if (ignored.indexOf(key) == -1 && marked.indexOf(key) == -1) {
						question = key
						break
					}
				}

				let parent_form = form.$parent ? form.$parent.$parent : form.$parent

				if (!question) {
					if (parent_form)
						runForm(parent_form)
					else {
						if (config && config.messages)
							sendMsg(config.messages.completed)

						let result = {}
						for (let question of marked)
							result[question] = answers[question]

						callback(result)
					}
				} else {
					let item = form[question]
					let last_form = item.$last

					let keyboard = []
					if (item.keyboard)
						keyboard = item.keyboard.slice()

					let cancel = false
					let back = false

					if (config && config.buttons) {
						let buttons = []
						if (config.buttons.cancel) {
							buttons.push(config.buttons.cancel)
							cancel = true
						}

						if (config.buttons.back && (last_form || parent_form)) {
							buttons.push(config.buttons.back)
							back = true
						}

						if (buttons.length)
							keyboard.push(buttons)
					}

					sendMsg(item.question, keyboard)
					this.waitForRequest.then($ => {
						if (cancel && $.message.text == config.buttons.cancel) {
							if (config.messages)
								sendMsg(config.messages.canceled)

							callback({})
						} else if (back && $.message.text == config.buttons.back) {
							if (last_form) {
								clearForm(last_form)
								runForm(form)
							} else {
								clearForm(parent_form)
								runForm(parent_form)
							}
						} else {
							if (item.validator) {
								if (!item.validator($.message)) {
									sendMsg(item.error)
									return runForm(form)
								}
							} else if (!checkKeyboard(keyboard, $.message.text)) {
								sendMsg(item.error)
								return runForm(form)
							}

							marked.push(question)

							if ($.message.text)
								answers[question] = item.values ? item.values[$.message.text] : $.message.text
							else if ($.message.location)
								answers[question] = $.message.location
							else if ($.message.photo)
								answers[question] = $.message.photo
							else if ($.message.contact)
								answers[question] = $.message.contact.phoneNumber
							else
								throw new Error('Unsupported answer type!')

							runForm(item[$.message.text] || form)
						}
					})
				}
			}

			makeMap(root_form)
			runForm(root_form)
		}

		get name() {
			return 'runMultiForm'
		}
	}

	tg.addScopeExtension(MultiFormScopeExtension)
}
<commit_msg>save form before use<commit_after>//////////////////////////////////////////////////////////
/*
	module: index.js
	author: Evgeniy Litvinov <raytwitty@gmail.com>
	description: extensions of telegram-node-bot module
*/
//////////////////////////////////////////////////////////

'use strict'

require('js-standard-library-extensions')

module.exports = (Telegram, tg) => {
	class MultiFormScopeExtension extends Telegram.BaseScopeExtension {
		process(root_form, callback, config) {
			root_form = Object.copy(root_form)
			let marked = []
			let answers = {}
			let ignored = ['$name', '$parent', '$last', 'values']

			let checkKeyboard = (keyboard, answer) => {
				for (let value of keyboard) {
					if (value == answer || (Array.isArray(value) && checkKeyboard(value, answer)))
						return true
				}
			}

			let sendMsg = (text, keyboard) => {
				if (text) {
					this.sendMessage(text, {
						disable_web_page_preview: true,
						parse_mode: 'HTML',
						reply_markup: JSON.stringify(keyboard ? {
							one_time_keyboard: true,
							resize_keyboard: true,
							keyboard: keyboard
						} : {remove_keyboard: true})
					})
				}
			}

			let makeMap = form => {
				let last
				Object.forEach(form, (key, value) => {
					if (ignored.indexOf(key) == -1 && isObject(value)) {
						makeMap(value)

						value.$name = key
						value.$parent = form
						value.$last = last
						last = value
					}
				})
			}

			let clearForm = form => {
				marked.remove(form.$name)

				Object.forEach(form, (key, value) => {
					if (ignored.indexOf(key) == -1 && isObject(value))
						clearForm(value)
				})
			}

			let runForm = form => {
				let question
				for (let key in form) {
					if (ignored.indexOf(key) == -1 && marked.indexOf(key) == -1) {
						question = key
						break
					}
				}

				let parent_form = form.$parent ? form.$parent.$parent : form.$parent

				if (!question) {
					if (parent_form)
						runForm(parent_form)
					else {
						if (config && config.messages)
							sendMsg(config.messages.completed)

						let result = {}
						for (let question of marked)
							result[question] = answers[question]

						callback(result)
					}
				} else {
					let item = form[question]
					let last_form = item.$last

					let keyboard = []
					if (item.keyboard)
						keyboard = item.keyboard.slice()

					let cancel = false
					let back = false

					if (config && config.buttons) {
						let buttons = []
						if (config.buttons.cancel) {
							buttons.push(config.buttons.cancel)
							cancel = true
						}

						if (config.buttons.back && (last_form || parent_form)) {
							buttons.push(config.buttons.back)
							back = true
						}

						if (buttons.length)
							keyboard.push(buttons)
					}

					sendMsg(item.question, keyboard)
					this.waitForRequest.then($ => {
						if (cancel && $.message.text == config.buttons.cancel) {
							if (config.messages)
								sendMsg(config.messages.canceled)

							callback({})
						} else if (back && $.message.text == config.buttons.back) {
							if (last_form) {
								clearForm(last_form)
								runForm(form)
							} else {
								clearForm(parent_form)
								runForm(parent_form)
							}
						} else {
							if (item.validator) {
								if (!item.validator($.message)) {
									sendMsg(item.error)
									return runForm(form)
								}
							} else if (!checkKeyboard(keyboard, $.message.text)) {
								sendMsg(item.error)
								return runForm(form)
							}

							marked.push(question)

							if ($.message.text)
								answers[question] = item.values ? item.values[$.message.text] : $.message.text
							else if ($.message.location)
								answers[question] = $.message.location
							else if ($.message.photo)
								answers[question] = $.message.photo
							else if ($.message.contact)
								answers[question] = $.message.contact.phoneNumber
							else
								throw new Error('Unsupported answer type!')

							runForm(item[$.message.text] || form)
						}
					})
				}
			}

			makeMap(root_form)
			runForm(root_form)
		}

		get name() {
			return 'runMultiForm'
		}
	}

	tg.addScopeExtension(MultiFormScopeExtension)
}
<|endoftext|>


<commit_before>var archiver = require('archiver'),
    exec = require('child_process').exec,
    fs = require('fs'),
    mime = require('mime'),
    mkdirp = require('mkdirp'),
    nconf = require('nconf'),
    q = require('q'),
    winston = require('winston');

// Logging stuff
nconf.file({ file: './gebo.json' });
var logLevel = nconf.get('logLevel'),
    timeout = nconf.get('imagemagick').timeout;
var logger = new (winston.Logger)({ transports: [ new (winston.transports.Console)({ colorize: true }) ] });

/**
 * Convert a given file from one format to another
 *
 * @param string
 * @param string
 * @param string
 *
 * @return string
 */
function _convert(path, format, outdir) {
    var deferred = q.defer();

    if (!outdir) {
      outdir = '.';
    }

    var outputFileName = _getOutputFileName(path, format);

    // Set up time limit
    var executionTimer = setTimeout(function() {
            var kill = 'kill $(cat /tmp/' + _getOutputFileName(path, format) + '.pid)';
            exec(kill, function(err, stdout, stderr) {
                deferred.resolve({ error: 'Sorry, that file took too long to process' });
              });
        }, timeout);

    mkdirp(outdir, function(err, made) {
        if (err) {
          if (logLevel === 'trace') logger.error('gebo-imagemagick, mkdirp:', err);
          deferred.resolve({ error: err });
        }

        // PDFs may produce multiple images
        var command = 'convert ' + path + ' ' + outdir + '/';
        if (mime.lookup(path) === 'application/pdf') {
          command += '%0d_';
        }
        command += outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';

        if (logLevel === 'trace') logger.info('gebo-imagemagick:', command);

        exec(command, function(err, stdout, stderr) {
            clearInterval(executionTimer);
            if (err) {
              if (logLevel === 'trace') logger.error('gebo-imagemagick:', err);
              deferred.resolve({ error: err });
            }
            else {
              if (logLevel === 'trace' && stderr) logger.warn('gebo-imagemagick:', stderr);
              fs.realpath(outdir, function(err, resolvedPath) {
                    fs.readdir(resolvedPath, function(err, files) {
                        if (err) {
                          if (logLevel === 'trace') logger.error('gebo-imagemagick, fs.readdir:', err);
                          deferred.resolve({ error: err });
                        }
                        // Converting a PDF may potentially generate multiple files. I.e., one for each page.
                        if (files.length > 1) {
                          var zipFileName = resolvedPath + '/' + outputFileName + '.zip';
                          var output = fs.createWriteStream(zipFileName);
                          var archive = archiver('zip');

                          output.on('close', function() {
                                if (logLevel === 'trace') logger.info('gebo-imagemagick, archiver:', archive.pointer() + ' total bytes in ' + zipFileName);
                                deferred.resolve(zipFileName);
                            });

                          archive.on('error', function(err) {
                                if (logLevel === 'trace') logger.error('gebo-imagemagick, archiver:', err);
                                deferred.resolve({ error: err });
                            });

                          archive.pipe(output);

                          files.forEach(function(file) {
                                archive.append(fs.createReadStream(resolvedPath + '/' + file), { name: file });
                            });
                          archive.finalize(); }
                        else {
                          deferred.resolve(resolvedPath + '/' +  files[0]);
                        }
                    });
                });
            }
          });
      });

    return deferred.promise;
  };
exports.convert = _convert;

/**
 * Take the incoming filename and its extension
 * and return the hypothetical output filename
 *
 * @param string
 * @param string
 *
 * @return string
 */
function _getOutputFileName(path, extension) {
    var filename = path.split('/');
    filename = filename[filename.length - 1];
    filename = filename.split('.');

    // No extension found
    if (filename.length === 1) {
      return filename[0] + '.' + extension;
    }

    // Hidden file
    if (filename[0] === '') {
      filename = filename.slice(1);
      filename[0] = '.' + filename[0];
      if (filename.length === 1) {
        return filename[0] + '.' + extension;
      }
    }

    filename = filename.slice(0, -1);

    return filename + '.' + extension;
  };
exports.getOutputFileName = _getOutputFileName;

<commit_msg>Change ImageMagick command to ensure 100% quality (esp. on PDF->images)<commit_after>var archiver = require('archiver'),
    exec = require('child_process').exec,
    fs = require('fs'),
    mime = require('mime'),
    mkdirp = require('mkdirp'),
    nconf = require('nconf'),
    q = require('q'),
    winston = require('winston');

// Logging stuff
nconf.file({ file: './gebo.json' });
var logLevel = nconf.get('logLevel'),
    timeout = nconf.get('imagemagick').timeout;
var logger = new (winston.Logger)({ transports: [ new (winston.transports.Console)({ colorize: true }) ] });

/**
 * Convert a given file from one format to another
 *
 * @param string
 * @param string
 * @param string
 *
 * @return string
 */
function _convert(path, format, outdir) {
    var deferred = q.defer();

    if (!outdir) {
      outdir = '.';
    }

    var outputFileName = _getOutputFileName(path, format);

    // Set up time limit
    var executionTimer = setTimeout(function() {
            var kill = 'kill $(cat /tmp/' + _getOutputFileName(path, format) + '.pid)';
            exec(kill, function(err, stdout, stderr) {
                deferred.resolve({ error: 'Sorry, that file took too long to process' });
              });
        }, timeout);

    mkdirp(outdir, function(err, made) {
        if (err) {
          if (logLevel === 'trace') logger.error('gebo-imagemagick, mkdirp:', err);
          deferred.resolve({ error: err });
        }

        // PDFs may produce multiple images
//        var command = 'convert ' + path + ' ' + outdir + '/';
//        if (mime.lookup(path) === 'application/pdf') {
//          command += '%0d_';
//        }
//        command += outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';

        //application/octet-stream
        var command;
        var mimeType = mime.lookup(path);
        //if (logLevel === 'trace') console.log('gebo-imagemagick: no extension?', mimeType);
//        console.log('mimeType', mimeType);
        if (mimeType === 'application/pdf') {
          command = 'convert -interlace none -density 300 -quality 100 ' + path + ' ' + outdir + '/%0d_' + outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';
        }
        // Probably no extension
//        else if (mimeType ==='application/octet-stream') {
//          // Why do I need this? Comment it out and tests will fail
//          if (logLevel === 'trace') console.log('gebo-imagemagick: no extension?', mimeType);
//
//          command = 'convert ' + path + ' ' + outdir + '/' + outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';
//        }
        else {
          command = 'convert -quality 100 ' + path + ' ' + outdir + '/' + outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';
        }

//        var command;
//        if (mime.lookup(path) === 'application/pdf') {
//          command = 'convert -interlace none -density 300 -quality 100 ' +
//                    path + ' ' + outdir + '/%0d_' + outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';
//        }
//        else {
//          command = 'convert -quality 100 ' + path + ' ' + outdir + '/' + outputFileName + ' & echo $! > /tmp/' + outputFileName + '.pid';
//        }

        if (logLevel === 'trace') logger.info('gebo-imagemagick:', command);

        exec(command, function(err, stdout, stderr) {
            clearInterval(executionTimer);
            if (err) {
              if (logLevel === 'trace') logger.error('gebo-imagemagick:', err);
              deferred.resolve({ error: err });
            }
            else {
              if (logLevel === 'trace' && stderr) logger.warn('gebo-imagemagick:', stderr);
              fs.realpath(outdir, function(err, resolvedPath) {
                    fs.readdir(resolvedPath, function(err, files) {
                        if (err) {
                          if (logLevel === 'trace') logger.error('gebo-imagemagick, fs.readdir:', err);
                          deferred.resolve({ error: err });
                        }
                        // Converting a PDF may potentially generate multiple files. I.e., one for each page.
                        if (files.length > 1) {
                          var zipFileName = resolvedPath + '/' + outputFileName + '.zip';
                          var output = fs.createWriteStream(zipFileName);
                          var archive = archiver('zip');

                          output.on('close', function() {
                                if (logLevel === 'trace') logger.info('gebo-imagemagick, archiver:', archive.pointer() + ' total bytes in ' + zipFileName);
                                deferred.resolve(zipFileName);
                            });

                          archive.on('error', function(err) {
                                if (logLevel === 'trace') logger.error('gebo-imagemagick, archiver:', err);
                                deferred.resolve({ error: err });
                            });

                          archive.pipe(output);

                          files.forEach(function(file) {
                                archive.append(fs.createReadStream(resolvedPath + '/' + file), { name: file });
                            });
                          archive.finalize(); }
                        else {
                          deferred.resolve(resolvedPath + '/' +  files[0]);
                        }
                    });
                });
            }
          });
      });

    return deferred.promise;
  };
exports.convert = _convert;

/**
 * Take the incoming filename and its extension
 * and return the hypothetical output filename
 *
 * @param string
 * @param string
 *
 * @return string
 */
function _getOutputFileName(path, extension) {
    var filename = path.split('/');
    filename = filename[filename.length - 1];
    filename = filename.split('.');

    // No extension found
    if (filename.length === 1) {
      return filename[0] + '.' + extension;
    }

    // Hidden file
    if (filename[0] === '') {
      filename = filename.slice(1);
      filename[0] = '.' + filename[0];
      if (filename.length === 1) {
        return filename[0] + '.' + extension;
      }
    }

    filename = filename.slice(0, -1);

    return filename + '.' + extension;
  };
exports.getOutputFileName = _getOutputFileName;

<|endoftext|>


<commit_before>/* @flow */

import Path from 'path'
import { CompositeDisposable, TextEditor } from 'atom'
import { exec, findCached, findCachedAsync } from 'atom-linter'
import { shouldTriggerAutocomplete } from 'atom-autocomplete'
import {
  INIT_MESSAGE,
  RECHECKING_MESSAGE,
  injectPosition,
  toStatusLinterMessages,
  toCoverageLinterMessages,
  toAutocompleteSuggestions,
} from './helpers'
import CoverageView from './coverage-view'
import type { CoverageObject } from './types'

const spawnedServers: Set<string> = new Set()
const defaultFlowFile = Path.resolve(__dirname, '..', 'vendor', '.flowconfig')

export default {
  activate() {
    // eslint-disable-next-line global-require
    require('atom-package-deps').install('flow-ide', true)

    this.subscriptions = new CompositeDisposable()
    this.subscriptions.add(atom.config.observe('flow-ide.executablePath', (executablePath) => {
      this.executablePath = executablePath
    }))
    this.subscriptions.add(atom.config.observe('flow-ide.onlyIfAppropriate', (onlyIfAppropriate) => {
      this.onlyIfAppropriate = onlyIfAppropriate
    }))
    this.subscriptions.add(atom.config.observe('flow-ide.showUncovered', (showUncovered) => {
      this.showUncovered = showUncovered
      // lint again so that the coverage actually updates
      const view = atom.views.getView(atom.workspace.getActiveTextEditor())
      if (view) {
        atom.commands.dispatch(view, 'linter:lint')
      }
    }))
  },

  async getExecutablePath(fileDirectory: string): Promise<string> {
    return (
      await findCachedAsync(fileDirectory, 'node_modules/.bin/flow') ||
      this.executablePath ||
      'flow'
    )
  },

  deactivate() {
    this.subscriptions.dispose()
    spawnedServers.forEach((rootDirectory) => {
      const executable = findCached(rootDirectory, 'node_modules/.bin/flow') || this.executablePath || 'flow'
      exec(executable, ['stop'], {
        cwd: rootDirectory,
        timeout: 60 * 1000,
        detached: true,
        ignoreExitCode: true,
      }).catch(() => null) // <-- ignore all errors
    })
  },

  provideLinter(): Object[] {
    return [this.provideStatusLinter(), this.provideCoverageLinter()]
  },

  provideStatusLinter(): Object {
    const linter = {
      name: 'Flow IDE',
      scope: 'project',
      grammarScopes: ['source.js', 'source.js.jsx'],
      lintsOnChange: false,
      // eslint-disable-next-line arrow-parens
      lint: async (textEditor) => {
        let configFile
        const filePath = textEditor.getPath()
        const fileDirectory = Path.dirname(filePath)

        if (this.onlyIfAppropriate) {
          configFile = await findCachedAsync(fileDirectory, '.flowconfig')
          if (!configFile) {
            return []
          }
        } else {
          return []
        }

        const executable = await this.getExecutablePath(fileDirectory)

        let result
        try {
          result = await exec(executable, ['status', '--json'], {
            cwd: fileDirectory,
            ignoreExitCode: true,
            timeout: 60 * 1000,
            uniqueKey: 'flow-ide-linter',
          })
          if (result === null) {
            return null
          }
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 && configFile) {
            spawnedServers.add(Path.dirname(configFile))
          }
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return linter.lint(textEditor)
          } else if (error.code === 'ENOENT') {
            throw new Error('Unable to find `flow` executable.')
          } else {
            throw error
          }
        }

        return toStatusLinterMessages(result)
      },
    }
    return linter
  },
  provideCoverageLinter() {
    const linter = {
      name: 'Flow IDE Coverage',
      scope: 'file',
      grammarScopes: ['source.js', 'source.js.jsx'],
      lintsOnChange: false,
      lint: async (textEditor: TextEditor) => {
        let configFile
        const filePath = textEditor.getPath()
        const fileDirectory = Path.dirname(filePath)

        if (this.onlyIfAppropriate) {
          configFile = await findCachedAsync(fileDirectory, '.flowconfig')
          if (!configFile) {
            return []
          }
        } else {
          return []
        }

        const executable = await this.getExecutablePath(fileDirectory)

        let result: string
        try {
          result = await exec(executable, ['coverage', filePath, '--json'], {
            cwd: fileDirectory,
            ignoreExitCode: true,
            timeout: 60 * 1000,
            uniqueKey: 'flow-ide-coverage',
          })
          if (result === null) {
            return null
          }
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 && configFile) {
            spawnedServers.add(Path.dirname(configFile))
          }
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return linter.lint(textEditor)
          } else if (error.code === 'ENOENT') {
            throw new Error('Unable to find `flow` executable.')
          } else {
            throw error
          }
        }

        const coverage: CoverageObject = JSON.parse(result)
        if (this.coverageView) {
          this.coverageView.update(coverage)
        }
        return this.showUncovered ? toCoverageLinterMessages(coverage) : []
      },
    }
    return linter
  },

  provideAutocomplete(): Object {
    const provider = {
      selector: '.source.js, .source.js.jsx',
      disableForSelector: '.comment',
      inclusionPriority: 100,
      // eslint-disable-next-line arrow-parens
      getSuggestions: async (params) => {
        const { editor, bufferPosition, activatedManually } = params
        let prefix = params.prefix
        const filePath = editor.getPath()
        if (!filePath) {
          // We not process files without filepath
          return []
        }

        const fileDirectory = Path.dirname(filePath)
        const fileContents = injectPosition(editor.getText(), editor, bufferPosition)
        let flowOptions = ['autocomplete', '--json', filePath]

        const configFile = await findCachedAsync(fileDirectory, '.flowconfig')
        if (!configFile) {
          if (this.onlyIfAppropriate) {
            return []
          }
          flowOptions = ['autocomplete', '--root', defaultFlowFile, '--json', filePath]
        }

        // NOTE: Fix for class properties autocompletion
        if (prefix === '.') {
          prefix = ''
        }

        if (!shouldTriggerAutocomplete({ activatedManually, bufferPosition, editor })) {
          return []
        }

        let result
        try {
          result = await exec(await this.getExecutablePath(fileDirectory), flowOptions, {
            cwd: fileDirectory,
            stdin: fileContents,
            timeout: 60 * 1000,
            uniqueKey: 'flow-ide-autocomplete',
          })
          if (result === null) {
            return []
          }
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 && configFile) {
            spawnedServers.add(Path.dirname(configFile))
          }
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return provider.getSuggestions(params)
          }
          throw error
        }

        return toAutocompleteSuggestions(result, prefix)
      },
    }
    return provider
  },

  consumeStatusBar(statusBar: any): void {
    this.coverageView = new CoverageView()
    this.coverageView.initialize()
    this.statusBar = statusBar.addLeftTile({ item: this.coverageView, priority: 10 })
  },
}
<commit_msg>:bug: update coverage in status bar on pane change<commit_after>/* @flow */

import Path from 'path'
import { CompositeDisposable, TextEditor } from 'atom'
import { exec, findCached, findCachedAsync } from 'atom-linter'
import { shouldTriggerAutocomplete } from 'atom-autocomplete'
import {
  INIT_MESSAGE,
  RECHECKING_MESSAGE,
  injectPosition,
  toStatusLinterMessages,
  toCoverageLinterMessages,
  toAutocompleteSuggestions,
} from './helpers'
import CoverageView from './coverage-view'
import type { CoverageObject } from './types'

const spawnedServers: Set<string> = new Set()
const defaultFlowFile = Path.resolve(__dirname, '..', 'vendor', '.flowconfig')

export default {
  activate() {
    // eslint-disable-next-line global-require
    require('atom-package-deps').install('flow-ide', true)

    this.subscriptions = new CompositeDisposable()
    this.subscriptions.add(atom.config.observe('flow-ide.executablePath', (executablePath) => {
      this.executablePath = executablePath
    }))
    this.subscriptions.add(atom.config.observe('flow-ide.onlyIfAppropriate', (onlyIfAppropriate) => {
      this.onlyIfAppropriate = onlyIfAppropriate
    }))
    this.subscriptions.add(atom.config.observe('flow-ide.showUncovered', (showUncovered) => {
      this.showUncovered = showUncovered
      // lint again so that the coverage actually updates
      const view = atom.views.getView(atom.workspace.getActiveTextEditor())
      if (view) {
        atom.commands.dispatch(view, 'linter:lint')
      }
    }))
    this.subscriptions.add(atom.workspace.onDidChangeActivePaneItem((item: ?TextEditor): void => {
      if (this.coverageView) {
        const coverage = this.coverages.get(item)
        if (coverage) {
          this.coverageView.update(coverage)
        } else {
          this.coverageView.reset()
        }
      }
    }))

    this.coverages = new WeakMap()
  },

  async getExecutablePath(fileDirectory: string): Promise<string> {
    return (
      await findCachedAsync(fileDirectory, 'node_modules/.bin/flow') ||
      this.executablePath ||
      'flow'
    )
  },

  deactivate() {
    this.subscriptions.dispose()
    spawnedServers.forEach((rootDirectory) => {
      const executable = findCached(rootDirectory, 'node_modules/.bin/flow') || this.executablePath || 'flow'
      exec(executable, ['stop'], {
        cwd: rootDirectory,
        timeout: 60 * 1000,
        detached: true,
        ignoreExitCode: true,
      }).catch(() => null) // <-- ignore all errors
    })
  },

  provideLinter(): Object[] {
    return [this.provideStatusLinter(), this.provideCoverageLinter()]
  },

  provideStatusLinter(): Object {
    const linter = {
      name: 'Flow IDE',
      scope: 'project',
      grammarScopes: ['source.js', 'source.js.jsx'],
      lintsOnChange: false,
      // eslint-disable-next-line arrow-parens
      lint: async (textEditor) => {
        let configFile
        const filePath = textEditor.getPath()
        const fileDirectory = Path.dirname(filePath)

        if (this.onlyIfAppropriate) {
          configFile = await findCachedAsync(fileDirectory, '.flowconfig')
          if (!configFile) {
            return []
          }
        } else {
          return []
        }

        const executable = await this.getExecutablePath(fileDirectory)

        let result
        try {
          result = await exec(executable, ['status', '--json'], {
            cwd: fileDirectory,
            ignoreExitCode: true,
            timeout: 60 * 1000,
            uniqueKey: 'flow-ide-linter',
          })
          if (result === null) {
            return null
          }
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 && configFile) {
            spawnedServers.add(Path.dirname(configFile))
          }
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return linter.lint(textEditor)
          } else if (error.code === 'ENOENT') {
            throw new Error('Unable to find `flow` executable.')
          } else {
            throw error
          }
        }

        return toStatusLinterMessages(result)
      },
    }
    return linter
  },
  provideCoverageLinter(): Object {
    const linter = {
      name: 'Flow IDE Coverage',
      scope: 'file',
      grammarScopes: ['source.js', 'source.js.jsx'],
      lintsOnChange: false,
      lint: async (textEditor: TextEditor) => {
        let configFile
        const filePath = textEditor.getPath()
        const fileDirectory = Path.dirname(filePath)

        if (this.onlyIfAppropriate) {
          configFile = await findCachedAsync(fileDirectory, '.flowconfig')
          if (!configFile) {
            return []
          }
        } else {
          return []
        }

        const executable = await this.getExecutablePath(fileDirectory)

        let result: string
        try {
          result = await exec(executable, ['coverage', filePath, '--json'], {
            cwd: fileDirectory,
            ignoreExitCode: true,
            timeout: 60 * 1000,
            uniqueKey: 'flow-ide-coverage',
          })
          if (result === null) {
            return null
          }
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 && configFile) {
            spawnedServers.add(Path.dirname(configFile))
          }
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return linter.lint(textEditor)
          } else if (error.code === 'ENOENT') {
            throw new Error('Unable to find `flow` executable.')
          } else {
            throw error
          }
        }

        const coverage: CoverageObject = JSON.parse(result)
        this.coverages.set(textEditor, coverage)
        if (this.coverageView) {
          this.coverageView.update(coverage)
        }
        return this.showUncovered ? toCoverageLinterMessages(coverage) : []
      },
    }
    return linter
  },

  provideAutocomplete(): Object {
    const provider = {
      selector: '.source.js, .source.js.jsx',
      disableForSelector: '.comment',
      inclusionPriority: 100,
      // eslint-disable-next-line arrow-parens
      getSuggestions: async (params) => {
        const { editor, bufferPosition, activatedManually } = params
        let prefix = params.prefix
        const filePath = editor.getPath()
        if (!filePath) {
          // We not process files without filepath
          return []
        }

        const fileDirectory = Path.dirname(filePath)
        const fileContents = injectPosition(editor.getText(), editor, bufferPosition)
        let flowOptions = ['autocomplete', '--json', filePath]

        const configFile = await findCachedAsync(fileDirectory, '.flowconfig')
        if (!configFile) {
          if (this.onlyIfAppropriate) {
            return []
          }
          flowOptions = ['autocomplete', '--root', defaultFlowFile, '--json', filePath]
        }

        // NOTE: Fix for class properties autocompletion
        if (prefix === '.') {
          prefix = ''
        }

        if (!shouldTriggerAutocomplete({ activatedManually, bufferPosition, editor })) {
          return []
        }

        let result
        try {
          result = await exec(await this.getExecutablePath(fileDirectory), flowOptions, {
            cwd: fileDirectory,
            stdin: fileContents,
            timeout: 60 * 1000,
            uniqueKey: 'flow-ide-autocomplete',
          })
          if (result === null) {
            return []
          }
        } catch (error) {
          if (error.message.indexOf(INIT_MESSAGE) !== -1 && configFile) {
            spawnedServers.add(Path.dirname(configFile))
          }
          if (error.message.indexOf(INIT_MESSAGE) !== -1 || error.message.indexOf(RECHECKING_MESSAGE) !== -1) {
            return provider.getSuggestions(params)
          }
          throw error
        }

        return toAutocompleteSuggestions(result, prefix)
      },
    }
    return provider
  },

  consumeStatusBar(statusBar: any): void {
    this.coverageView = new CoverageView()
    this.coverageView.initialize()
    this.statusBar = statusBar.addLeftTile({ item: this.coverageView, priority: 10 })
  },
}
<|endoftext|>


<commit_before>'use strict';

const Objection = require('objection');
const Model = Objection.Model;
const Knex = require('knex');

const Path = require('path');
const Hoek = require('hoek');
const Joi = require('joi');
const Schema = require('./schema');
const Package = require('../package.json');
const Items = require('items');

const internals = {};

exports.register = (server, options, next) => {

    Joi.assert(options, Schema.plugin, 'Bad plugin options passed to schwifty.');

    const rootState = internals.state(server.root);

    let userOptions = Hoek.shallow(options);

    if (options.models) {
        userOptions.models = options.models;
    }

    if (!rootState.setup) {

        rootState.collector = {
            models: {},
            teardownOnStop: null // Not set, effectively defaults true
        };

        // Here's the ORM!

        server.decorate('server', 'schwifty', internals.schwifty);
        server.decorate('server', 'models', internals.models((ctx) => ctx, 'realm'));
        server.decorate('request', 'models', internals.models((ctx) => ctx.server, 'route.realm'));
        server.decorate('server', 'knex', internals.knex((ctx) => ctx, 'realm'));
        server.decorate('request', 'knex', internals.knex((ctx) => ctx.server, 'route.realm'));
        server.ext('onPreStart', internals.initialize);
        server.ext('onPostStop', internals.stop);

        rootState.setup = true;
    };

    const rootCollector = rootState.collector;

    // Decide whether server stop should teardown

    if (typeof options.teardownOnStop !== 'undefined') {
        Hoek.assert(rootCollector.teardownOnStop === null, 'Schwifty\'s teardownOnStop option can only be specified once.');
        rootCollector.teardownOnStop = options.teardownOnStop;
    }

    userOptions = internals.registrationConfig(userOptions);
    server.root.schwifty(userOptions);

    return next();
};

exports.register.attributes = {
    pkg: Package,
    multiple: true
};

// Massage registration config for use with rejoice
internals.registrationConfig = (options) => {

    const config = Hoek.shallow(options);

    delete config.teardownOnStop;

    // Resolve models

    if (typeof config.models === 'string') {
        if (Path.isAbsolute(config.models)) {
            config.models = require(config.models);
        }
        else {
            config.models = require(Path.resolve(process.cwd(), config.models));
        }
    }

    return config;
};

exports.Model = class SchwiftyModel extends Model {

    // $beforeInsert() {
    //   this.createdAt = new Date().toISOString();
    // };

    // $beforeUpdate() {
    //   this.updatedAt = new Date().toISOString();
    // };

    static parseValidationError(err) {

        // Implement this if you'd like to further parse Joi's error.details
        return err;
    }

    $validate(json, options) {

        if (!json) {
            // eslint complains about setting json to 'this'
            const self = this;
            json = self;
        }

        if (!options) {
            options = {};
        }

        const ModelClass = this.constructor;

        const joiSchema = ModelClass.schema;

        if (!joiSchema || options.skipValidation) {
            return json;
        }

        let validation = Joi.validate(json, joiSchema);

        if (validation.error) {

            throw new Objection.ValidationError(SchwiftyModel.parseValidationError(validation.error.details));
        }

        validation = validation.value;
        this.$afterValidate(validation, options);

        return validation;
    }
};

internals.initialize = function (server, next) {

    const rootCollector = internals.state(server.root).collector;

    Object.keys(rootCollector.knexGroups).forEach((key) => {

        const knexGroup = rootCollector.knexGroups[key];
        const models = knexGroup.models;

        models.forEach((modelName) => {

            modelName = modelName.toLowerCase();
            const model = rootCollector.models[modelName];
            const modelKnexed = model.bindKnex(knexGroup.knex);
            rootCollector.models[modelName] = modelKnexed;
        });
    });

    return next();
};

internals.stop = function (server, next) {

    const rootCollector = internals.state(server.root).collector;

    // Do not teardown if specifically asked not to
    if (rootCollector.teardownOnStop === false) {
        return next();
    }

    const rootKnex = internals.state(server.root).knex;

    const knexConnections = [rootKnex];

    Object.keys(rootCollector.knexGroups).forEach((key) => {

        knexConnections.push(rootCollector.knexGroups[key].knex);
    });

    rootKnex.destroy((err) => {

        // destroy() all other connection pools
        Items.parallel(knexConnections, (item, nxt) => {

            // If the 'item' (a knex) is the default rootKnex
            if (item === rootKnex) {
                return nxt();
            }

            item.destroy(nxt);
        },
        (err) => {

            if (err) {
                throw new Error(err);
            }
            return next();
        });
    });
};

internals.schwifty = function (config) {

    let isModels = false;
    let userConfig;

    if (Array.isArray(config) || config.prototype instanceof Objection.Model) {

        // Array of models or single passed in
        isModels = true;
        userConfig = config;
    }
    else {
        userConfig = Hoek.shallow(config);
    }

    userConfig = Joi.validate(userConfig, Schema.schwifty);

    // Check for errors
    if (userConfig.error) {
        throw new Error(userConfig.error.message);
    }
    else {
        userConfig = userConfig.value;
    }

    if (isModels === true) {
        userConfig = { models: userConfig };
    }

    userConfig.models = userConfig.models || [];

    // Collect models ensuring no dupes
    const rootCollector = internals.state(this.root).collector;

    const modelIds = userConfig.models.map((model) => new model().constructor.name);

    modelIds.forEach((id, index) => {

        // Classnames are often first-capital
        id = id.toLowerCase();
        Hoek.assert(!rootCollector.models[id], `Model definition with tableName "${id}" has already been registered.`);
        rootCollector.models[id] = userConfig.models[index];

        Hoek.assert(rootCollector.models[id].tableName, 'Model definition must have "static get tableName(){ return \'myTableName\' }"');
    });

    /*
        A knexGroup is a knexConfig db connection plus the models that are going there,
        the default is the root server's connection.
    */
    const knexGroup = {
        models: [],
        knex: {}
    };

    const state = internals.state(this);

    if (userConfig.knexConfig && typeof userConfig.knexConfig !== 'undefined') {
        Hoek.assert(typeof state.knexGroupId === 'undefined', 'Only one knexConfig allowed per server or plugin');
    }

    // Check if this state already has a knexGroup associated with it
    if (state.knexGroupId) {

        // The knexGroupId exists so add to models already there, also no need to continue so return here
        const models = rootCollector.knexGroups[state.knexGroupId].models;
        rootCollector.knexGroups[state.knexGroupId].models = models.concat(modelIds);
        return;
    }

    // Handle the knex instance
    if (userConfig.knexConfig) {

        const knexInstance = Knex(userConfig.knexConfig);

        knexGroup.knex = knexInstance;

        // Set the root knex connection if not there
        if (typeof internals.state(this.root).knex === 'undefined') {
            internals.state(this.root).knex = knexInstance;
        }
    }
    else {

        // By default the knex connection is the root server's.
        Hoek.assert(internals.state(this.root).knex, 'Must have root server knexConfig set before adding more models');
        knexGroup.knex = internals.state(this.root).knex;
    }

    // Now keep track of which plugins have which knex connections
    // modelIds is an array
    knexGroup.models = modelIds;
    rootCollector.knexGroups = rootCollector.knexGroups || {};

    const randId = internals.randomId();
    state.knexGroupId = randId;

    rootCollector.knexGroups[randId] = knexGroup;
};

internals.models = (serverFrom, realmPath) => {

    return function (all) {

        const rootCollector = internals.state(serverFrom(this).root).collector;

        if (Object.keys(rootCollector.models).length === 0) {
            return {};
        }

        if (all) {
            return rootCollector.models;
        }

        const modelObj = {};
        const knexGroupId = Hoek.reach(this, `${realmPath}.plugins.schwifty.knexGroupId`);

        const models = rootCollector.knexGroups[knexGroupId].models;

        for (let i = 0; i < models.length; ++i) {
            const modelName = models[i].toLowerCase();
            modelObj[modelName] = rootCollector.models[modelName];
        }

        return modelObj;
    };
};

internals.knex = function (serverFrom, realmPath) {

    return function () {

        const rootCollector = internals.state(serverFrom(this).root).collector;
        const knexGroupId = Hoek.reach(this, `${realmPath}.plugins.schwifty.knexGroupId`);
        return rootCollector.knexGroups[knexGroupId].knex;
    };
};

internals.randomId = () => {

    // new Date().getTime() with 2 random letters on the end should be sufficient
    const alph = 'abcdefghijklmnopqrstuvwxyz';
    let randId = new Date().getTime();
    randId += alph.charAt(Math.floor(Math.random() * alph.length));
    randId += alph.charAt(Math.floor(Math.random() * alph.length));

    return randId;
};

internals.state = (srv) => {

    const state = srv.realm.plugins.schwifty = srv.realm.plugins.schwifty || {};
    return state;
};
<commit_msg>Fix err chase<commit_after>'use strict';

const Objection = require('objection');
const Model = Objection.Model;
const Knex = require('knex');

const Path = require('path');
const Hoek = require('hoek');
const Joi = require('joi');
const Schema = require('./schema');
const Package = require('../package.json');
const Items = require('items');

const internals = {};

exports.register = (server, options, next) => {

    Joi.assert(options, Schema.plugin, 'Bad plugin options passed to schwifty.');

    const rootState = internals.state(server.root);

    let userOptions = Hoek.shallow(options);

    if (options.models) {
        userOptions.models = options.models;
    }

    if (!rootState.setup) {

        rootState.collector = {
            models: {},
            teardownOnStop: null // Not set, effectively defaults true
        };

        // Here's the ORM!

        server.decorate('server', 'schwifty', internals.schwifty);
        server.decorate('server', 'models', internals.models((ctx) => ctx, 'realm'));
        server.decorate('request', 'models', internals.models((ctx) => ctx.server, 'route.realm'));
        server.decorate('server', 'knex', internals.knex((ctx) => ctx, 'realm'));
        server.decorate('request', 'knex', internals.knex((ctx) => ctx.server, 'route.realm'));
        server.ext('onPreStart', internals.initialize);
        server.ext('onPostStop', internals.stop);

        rootState.setup = true;
    };

    const rootCollector = rootState.collector;

    // Decide whether server stop should teardown

    if (typeof options.teardownOnStop !== 'undefined') {
        Hoek.assert(rootCollector.teardownOnStop === null, 'Schwifty\'s teardownOnStop option can only be specified once.');
        rootCollector.teardownOnStop = options.teardownOnStop;
    }

    userOptions = internals.registrationConfig(userOptions);
    server.root.schwifty(userOptions);

    return next();
};

exports.register.attributes = {
    pkg: Package,
    multiple: true
};

// Massage registration config for use with rejoice
internals.registrationConfig = (options) => {

    const config = Hoek.shallow(options);

    delete config.teardownOnStop;

    // Resolve models

    if (typeof config.models === 'string') {
        if (Path.isAbsolute(config.models)) {
            config.models = require(config.models);
        }
        else {
            config.models = require(Path.resolve(process.cwd(), config.models));
        }
    }

    return config;
};

exports.Model = class SchwiftyModel extends Model {

    // $beforeInsert() {
    //   this.createdAt = new Date().toISOString();
    // };

    // $beforeUpdate() {
    //   this.updatedAt = new Date().toISOString();
    // };

    static parseValidationError(err) {

        // Implement this if you'd like to further parse Joi's error.details
        return err;
    }

    $validate(json, options) {

        if (!json) {
            // eslint complains about setting json to 'this'
            const self = this;
            json = self;
        }

        if (!options) {
            options = {};
        }

        const ModelClass = this.constructor;

        const joiSchema = ModelClass.schema;

        if (!joiSchema || options.skipValidation) {
            return json;
        }

        let validation = Joi.validate(json, joiSchema);

        if (validation.error) {

            throw new Objection.ValidationError(SchwiftyModel.parseValidationError(validation.error.details));
        }

        validation = validation.value;
        this.$afterValidate(validation, options);

        return validation;
    }
};

internals.initialize = function (server, next) {

    const rootCollector = internals.state(server.root).collector;

    Object.keys(rootCollector.knexGroups).forEach((key) => {

        const knexGroup = rootCollector.knexGroups[key];
        const models = knexGroup.models;

        models.forEach((modelName) => {

            modelName = modelName.toLowerCase();
            const model = rootCollector.models[modelName];
            const modelKnexed = model.bindKnex(knexGroup.knex);
            rootCollector.models[modelName] = modelKnexed;
        });
    });

    return next();
};

internals.stop = function (server, next) {

    const rootCollector = internals.state(server.root).collector;

    // Do not teardown if specifically asked not to
    if (rootCollector.teardownOnStop === false) {
        return next();
    }

    const rootKnex = internals.state(server.root).knex;

    const knexConnections = [rootKnex];

    Object.keys(rootCollector.knexGroups).forEach((key) => {

        const knexConn = rootCollector.knexGroups[key].knex;

        if (knexConn !== rootKnex) {
            knexConnections.push(knexConn);
        }
    });

    Items.parallel(knexConnections, (item, nxt) => item.destroy(nxt), next);
};

internals.schwifty = function (config) {

    let isModels = false;
    let userConfig;

    if (Array.isArray(config) || config.prototype instanceof Objection.Model) {

        // Array of models or single passed in
        isModels = true;
        userConfig = config;
    }
    else {
        userConfig = Hoek.shallow(config);
    }

    userConfig = Joi.validate(userConfig, Schema.schwifty);

    // Check for errors
    if (userConfig.error) {
        throw new Error(userConfig.error.message);
    }
    else {
        userConfig = userConfig.value;
    }

    if (isModels === true) {
        userConfig = { models: userConfig };
    }

    userConfig.models = userConfig.models || [];

    // Collect models ensuring no dupes
    const rootCollector = internals.state(this.root).collector;

    const modelIds = userConfig.models.map((model) => new model().constructor.name);

    modelIds.forEach((id, index) => {

        // Classnames are often first-capital
        id = id.toLowerCase();
        Hoek.assert(!rootCollector.models[id], `Model definition with tableName "${id}" has already been registered.`);
        rootCollector.models[id] = userConfig.models[index];

        Hoek.assert(rootCollector.models[id].tableName, 'Model definition must have "static get tableName(){ return \'myTableName\' }"');
    });

    /*
        A knexGroup is a knexConfig db connection plus the models that are going there,
        the default is the root server's connection.
    */
    const knexGroup = {
        models: [],
        knex: {}
    };

    const state = internals.state(this);

    if (userConfig.knexConfig && typeof userConfig.knexConfig !== 'undefined') {
        Hoek.assert(typeof state.knexGroupId === 'undefined', 'Only one knexConfig allowed per server or plugin');
    }

    // Check if this state already has a knexGroup associated with it
    if (state.knexGroupId) {

        // The knexGroupId exists so add to models already there, also no need to continue so return here
        const models = rootCollector.knexGroups[state.knexGroupId].models;
        rootCollector.knexGroups[state.knexGroupId].models = models.concat(modelIds);
        return;
    }

    // Handle the knex instance
    if (userConfig.knexConfig) {

        const knexInstance = Knex(userConfig.knexConfig);

        knexGroup.knex = knexInstance;

        // Set the root knex connection if not there
        if (typeof internals.state(this.root).knex === 'undefined') {
            internals.state(this.root).knex = knexInstance;
        }
    }
    else {

        // By default the knex connection is the root server's.
        Hoek.assert(internals.state(this.root).knex, 'Must have root server knexConfig set before adding more models');
        knexGroup.knex = internals.state(this.root).knex;
    }

    // Now keep track of which plugins have which knex connections
    // modelIds is an array
    knexGroup.models = modelIds;
    rootCollector.knexGroups = rootCollector.knexGroups || {};

    const randId = internals.randomId();
    state.knexGroupId = randId;

    rootCollector.knexGroups[randId] = knexGroup;
};

internals.models = (serverFrom, realmPath) => {

    return function (all) {

        const rootCollector = internals.state(serverFrom(this).root).collector;

        if (Object.keys(rootCollector.models).length === 0) {
            return {};
        }

        if (all) {
            return rootCollector.models;
        }

        const modelObj = {};
        const knexGroupId = Hoek.reach(this, `${realmPath}.plugins.schwifty.knexGroupId`);

        const models = rootCollector.knexGroups[knexGroupId].models;

        for (let i = 0; i < models.length; ++i) {
            const modelName = models[i].toLowerCase();
            modelObj[modelName] = rootCollector.models[modelName];
        }

        return modelObj;
    };
};

internals.knex = function (serverFrom, realmPath) {

    return function () {

        const rootCollector = internals.state(serverFrom(this).root).collector;
        const knexGroupId = Hoek.reach(this, `${realmPath}.plugins.schwifty.knexGroupId`);
        return rootCollector.knexGroups[knexGroupId].knex;
    };
};

internals.randomId = () => {

    // new Date().getTime() with 2 random letters on the end should be sufficient
    const alph = 'abcdefghijklmnopqrstuvwxyz';
    let randId = new Date().getTime();
    randId += alph.charAt(Math.floor(Math.random() * alph.length));
    randId += alph.charAt(Math.floor(Math.random() * alph.length));

    return randId;
};

internals.state = (srv) => {

    const state = srv.realm.plugins.schwifty = srv.realm.plugins.schwifty || {};
    return state;
};
<|endoftext|>