Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mnort9 committed Aug 16, 2015
0 parents commit 18e085f
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.gooseconrc
140 changes: 140 additions & 0 deletions bin/goosecon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/env node

var repl = require('repl');
var fs = require('fs');
var path = require('path');
var vm = require('vm');
var util = require('util');
var rc = require('rc');
var _ = require('underscore');
var chalk = require('chalk');

var argv = require('yargs')
.usage('Usage: $0 <command> [options]')
.command('goosecon', 'Run goosecon')
.alias('console')
.demand(1)
.option('mongo-db', {
describe: 'MongoDB URL'
})
.option('models-path', {
describe: 'Path to models directory'
})
.option('mongoose-path', {
describe: 'Path to mongoose'
})
.help('h')
.alias('h', 'help')
.argv;

// Override options
var config = rc('goosecon', {}, argv);

// console.log(config);

var mongoosePath = config.mongoosePath ? path.resolve(process.cwd() + config.mongoosePath) : 'mongoose';
var mongoose = require(mongoosePath);
var replServer;

mongoose.connect(config.mongoDb);

mongoose.connection.on('error', function(err) {
console.error('Unable to connect to db ' + config.mongoDb + '\n' + err);
process.exit(1);
});

function startReplServer () {
replServer = repl.start({
eval: function(cmd, context, filename, cb) {
var result;

try {
result = vm.runInContext(cmd, context, filename);
}
catch(err) { return cb(err); }

// instanceof doesn't work when mongoose version < 4
if (_.isObject(result) && (result instanceof mongoose.Query || result.constructor.name === 'Query')) {
result.exec(function(err, doc) {
if (err) return cb(err);
return cb(null, doc);
});
} else {
cb(null, result);
}
},
writer: function(val) {
if (!val) return '';

try {
val = JSON.parse(JSON.stringify(val));
console.log(util.inspect(val, { colors: true }));
return '';
}
catch(err) { console.error('Unable to stringify JSON'); }

console.log(val);
return ''; // Prevents 'undefined' output
}
});
}

function addModulesToContext() {
var moduleNames = [];
var files = _.compact(_.flatten([findModelFiles(), findOtherModules()]));

// Add models to repl context
files.forEach(function(file) {
var module;
try { module = require(file); }
catch(err) { return; }

// Get module name and capitalize first letter
var moduleName = path.basename(file, '.js');
moduleName = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);

replServer.context[moduleName] = module;
moduleNames.push(moduleName);
});

if (moduleNames)
console.log(chalk.grey('** Loaded: ') + chalk.red(moduleNames.join(', ')));
replServer.displayPrompt();
}

function findModelFiles() {
var modelsPath = config.modelsPath;
var files;

if (!modelsPath) {
var cwdFiles = fs.readdirSync(process.cwd());

// Search working directory for models directory
if (_.contains(cwdFiles, 'models'))
modelsPath = path.resolve(process.cwd() + '/' + 'models');
else
return;
}

files = fs.readdirSync(modelsPath);
files = files.map(function(file) { return path.resolve(modelsPath + '/' + file); });

return files;
}

function findOtherModules() {
if (!config.modules) return;

// Convert command line argument to array
var modulesDirectories = typeof config.modules === 'string' ? [config.modules] : config.modules;

var modules = modulesDirectories.map(function(modulesDirPath) {
var files = fs.readdirSync(modulesDirPath);
return files.map(function(file) { return path.resolve(modulesDirPath + '/' + file); });
});

return modules;
}

startReplServer();
addModulesToContext();
26 changes: 26 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "goosecon",
"version": "0.1.0",
"description": "A Mongoose console that auto-loads models and other modules",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC",
"dependencies": {
"chalk": "^1.1.0",
"mongoose": "^4.1.2",
"rc": "^1.1.0",
"underscore": "^1.8.3",
"yargs": "^3.18.0"
},
"devDependencies": {
"chai": "^3.2.0",
"mocha": "^2.2.5"
},
"bin": {
"console": "./bin/goosecon.js"
},
"engines": {
"node": ">=0.10.x"
}
}
91 changes: 91 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
var spawn = require('child_process').spawn;
var expect = require('chai').expect;
var path = require('path');
var chalk = require('chalk');

describe('mongoose-console', function() {
var replServer;
var filePath = path.resolve(__dirname + "/../bin/console.js");

before(function() {
replServer = spawn('node', [filePath, 'console', '--mongo-db', 'mongodb://localhost/test', '--models-path', './test/models', '--modules', './test/modules']);

var result = '';
var err = '';

replServer.stdout.on('data', function(data) {
result += data;
// console.log(result);
});
replServer.stderr.on('data', function(data) {
err += data;
// console.log(err);
});
});

after(function() {
replServer.kill();
});

it('Throws error if not connected to db', function(done) {
var cp = spawn('node', [filePath, 'console']);

var err = '';
cp.stderr.on('data', function(data) { err += data; });
cp.on('exit', function (code) {
expect(err).contains('Unable to connect to db');
expect(code).to.equal(1);
done();
});
});

it('Loads models into context', function(done) {
test('Person.name', function(err, result) {
expect(err).to.be.empty;
expect(result).to.equal('model');
done();
});
});

it('Loads modules into context', function(done) {
test('typeof Service', function(err, result) {
expect(err).to.be.empty;
expect(result).to.equal('object');
done();
});
});

function test(cmd, cb) {
var result = '';
var err = '';
var timer;

replServer.stdout.on('data', function(data) { result += data; });
replServer.stderr.on('data', function(data) { err += data; });

replServer.stdin.write(cmd + '\n');

function finish() {
if (result.length === 0 && err.length === 0) {
timer = setTimeout(finish, 500);
return;
}

replServer.stdout.removeAllListeners('data');
replServer.stderr.removeAllListeners('data');
return cb(err, clean(result));
}
timer = setTimeout(finish, 500);
}

// Removes ANSI colors and extracts output between quotes
function clean(string) {
string = chalk.stripColor(string);
var substringMatches = string.match(/'([^']+)'/);

if (substringMatches.length > 1)
string = substringMatches[1];

return string;
}
});
8 changes: 8 additions & 0 deletions test/models/person.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;

var personSchema = new Schema({
name: String
});

module.exports = mongoose.model('Person', personSchema);
3 changes: 3 additions & 0 deletions test/modules/service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports.hello = function() {
console.log('Hello World');
};

0 comments on commit 18e085f

Please sign in to comment.