Merge pull request #241 from wibblymat/issue-219

Add an init command that generates a component.json (Fixes #219)
This commit is contained in:
André Cruz
2013-02-08 15:55:18 -08:00
10 changed files with 349 additions and 1 deletions

View File

@@ -16,6 +16,7 @@ module.exports = {
'link': require('./link'),
'lookup': require('./lookup'),
'info': require('./info'),
'init': require('./init'),
'register': require('./register'),
'search': require('./search'),
'cache-clean': require('./cache-clean'),

141
lib/commands/init.js Normal file
View File

@@ -0,0 +1,141 @@
// ==========================================
// BOWER: Init API
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var nopt = require('nopt');
var promptly = require('promptly');
var path = require('path');
var fs = require('fs');
var util = require('util');
var help = require('./help');
var Manager = require('../core/manager');
var config = require('../core/config');
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'] };
var commonIgnore = ['**/.*', 'node_modules', 'components'];
var Init = function () {
Manager.call(this);
};
util.inherits(Init, Manager);
Init.prototype.getDependenciesJSON = function () {
var dependencies = Object.keys(this.dependencies);
var remaining = dependencies.length;
var json = {};
dependencies.forEach(function (name) {
var pkg = this.dependencies[name][0];
pkg.on('loadJSON', function () {
json[pkg.name] = '~' + pkg.version;
remaining -= 1;
if (remaining === 0) {
this.manager.emit('loadDependencies', json);
}
}).loadJSON();
}, this);
if (remaining === 0) {
this.emit('loadDependencies', json);
}
return this;
};
Init.prototype.getMain = function (name) {
name = path.basename(name, '.js');
if (fs.existsSync(path.join(process.cwd(), 'index.js'))) {
return 'index.js';
} else if (fs.existsSync(path.join(process.cwd(), name + '.js'))) {
return name + '.js';
} else {
return null;
}
};
Init.prototype.showPrompt = function (question, cb) {
var prompt = question.prompt + ': [' + (question.yesno ? 'y' : question.value) + ']';
if (question.yesno) {
promptly.confirm(prompt, {'default': 'y'}, cb);
} else {
promptly.prompt(prompt, {'default': question.value}, cb);
}
this.emit('prompt', prompt);
};
Init.prototype.prompts = function (dependencies) {
var main = this.json.main || this.getMain(this.json.name) || '';
var questions = [
{key: 'name', prompt: 'name', value: this.json.name, yesno: false},
{key: 'version', prompt: 'version', value: this.json.version, yesno: false},
{key: 'main', prompt: 'main file', value: main, yesno: false},
{key: 'dependencies', prompt: 'add current components as dependencies? (y/n)', value: dependencies, yesno: true},
{key: 'ignore', prompt: 'add commonly ignored files to ignore list? (y/n)', value: commonIgnore, yesno: true}
];
var index = 0;
var question = questions[index];
var cb = function (err, value) {
this.json[question.key] = question.yesno ? (value ? question.value : []) : value;
index += 1;
if (index < questions.length) {
question = questions[index];
this.showPrompt(question, cb);
} else {
this.emit('prompts');
}
}.bind(this);
this.showPrompt(question, cb);
};
Init.prototype.save = function (data) {
fs.writeFileSync(path.join(this.cwd, config.json), JSON.stringify(data, null, 2));
};
module.exports = function () {
var init = new Init();
init
.on('resolveLocal', init.loadJSON.bind(init))
.on('loadJSON', init.getDependenciesJSON.bind(init))
.on('loadDependencies', init.prompts.bind(init))
.on('prompts', function () {
init.save(init.json);
init.emit('end');
})
.resolveLocal();
return init;
};
module.exports.Init = Init; // Purely for testing
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
if (options.help) return help('init');
return module.exports();
};
module.exports.completion = function (opts, cb) {
var word = opts.word;
// completing options?
if (word.charAt(0) === '-') {
return cb(null, Object.keys(optionTypes).map(function (option) {
return '--' + option;
}));
}
};

View File

@@ -33,7 +33,8 @@
"stable": "~0.1.2",
"rc": "~0.0.6",
"unzip": "~0.1.3",
"tar": "~0.1.13"
"tar": "~0.1.13",
"promptly": "~0.1.0"
},
"scripts": {
"postinstall": "node cleanup",

View File

@@ -0,0 +1,12 @@
Usage:
{{#cyan}}bower{{/cyan}} init
Options:
{{#yellow}}--no-color{{/yellow}} - Do not print colors
Description:
Creates a component.json file based on answers to questions

View File

@@ -0,0 +1,8 @@
{
"name": "backbone",
"version": "0.9.10",
"repository": {
"type": "git",
"url": "git://github.com/documentcloud/backbone.git"
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "jquery",
"version": "1.9.1",
"main": "./jquery.js",
"dependencies": {},
"gitHead": "975556d5d0e4ae21e67a97c0344d5dd89b49ea04",
"_id": "jquery@1.9.1",
"readme": "ERROR: No README.md file found!",
"description": "ERROR: No README.md file found!",
"repository": {
"type": "git",
"url": "git://github.com/components/jquery.git"
}
}

View File

@@ -0,0 +1,8 @@
{
"name": "underscore",
"version": "1.4.4",
"repository": {
"type": "git",
"url": "git://github.com/documentcloud/underscore.git"
}
}

View File

@@ -0,0 +1,8 @@
{
"name": "sample-package",
"version": "1.2.3",
"main": ["sample.js"],
"ignore": ["thingToIgnore"],
"dependencies" : {},
"custom": "A custom field"
}

View File

@@ -0,0 +1 @@
// An empty package

154
test/init.js Normal file
View File

@@ -0,0 +1,154 @@
/*jshint plusplus:false*/
var assert = require('assert');
var init = require('../lib/commands/init');
var cwd = process.cwd();
var setPackage = function (name) {
return function () {
cwd = process.cwd();
process.chdir(__dirname + '/assets/' + name);
};
};
var restorecwd = function () {
process.chdir(cwd);
};
describe('init', function () {
var savedData;
init.Init.prototype.save = function (data) {
savedData = data;
};
describe('defaults', function () {
before(setPackage('package-new'));
after(restorecwd);
it('Should ask you five questions and output default answers', function (next) {
var counter = 0;
var questions = [
'name: [package-new]',
'version: [0.0.0]',
'main file: [index.js]',
'add current components as dependencies? (y/n): [y]',
'add commonly ignored files to ignore list? (y/n): [y]'
];
init()
.on('prompt', function (prompt) {
assert.strictEqual(prompt, questions[counter++]);
process.stdin.emit('data', '\n');
})
.on('end', function () {
assert.strictEqual(counter, 5);
assert.deepEqual(savedData, {
name: 'package-new',
version: '0.0.0',
main: 'index.js',
dependencies: {},
ignore: ['**/.*', 'node_modules', 'components']
});
next();
});
});
});
describe('non-defaults', function () {
before(setPackage('package-new'));
after(restorecwd);
it('Should use your answers', function (next) {
var index = 0;
var answers = ['different-name', '2.3.1', 'other.js', 'n', 'n'];
init()
.on('prompt', function () {
process.stdin.emit('data', answers[index++] + '\n');
})
.on('end', function () {
assert.deepEqual(savedData, {
name: 'different-name',
version: '2.3.1',
main: 'other.js',
dependencies: {},
ignore: []
});
next();
});
});
});
describe('existing JSON', function () {
before(setPackage('package-existing-json'));
after(restorecwd);
it('Uses the existing values as defaults', function (next) {
var counter = 0;
var questions = [
'name: [sample-package]',
'version: [1.2.3]',
'main file: [sample.js]',
'add current components as dependencies? (y/n): [y]',
'add commonly ignored files to ignore list? (y/n): [y]'
];
init()
.on('prompt', function (prompt) {
assert.strictEqual(prompt, questions[counter++]);
process.stdin.emit('data', '\n');
})
.on('end', function () {
assert.deepEqual(savedData, {
'name': 'sample-package',
'version': '1.2.3',
'main': ['sample.js'],
'dependencies': {},
'ignore': [
'**/.*',
'node_modules',
'components'
],
'custom': 'A custom field'
});
next();
});
});
});
describe('existing dependencies', function () {
before(setPackage('package-existing-components'));
after(restorecwd);
it('Should output the correct components and versions', function (next) {
init()
.on('prompt', function () {
process.stdin.emit('data', '\n');
})
.on('end', function () {
assert.deepEqual(savedData, {
'name': 'package-existing-components',
'version': '0.0.0',
'main': '',
'dependencies': {
'backbone': '~0.9.10',
'jquery': '~1.9.1',
'underscore': '~1.4.4'
},
'ignore': [
'**/.*',
'node_modules',
'components'
]
});
next();
});
});
});
});