mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Merge pull request #241 from wibblymat/issue-219
Add an init command that generates a component.json (Fixes #219)
This commit is contained in:
@@ -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
141
lib/commands/init.js
Normal 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;
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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",
|
||||
|
||||
12
templates/help-init.mustache
Normal file
12
templates/help-init.mustache
Normal 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
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "backbone",
|
||||
"version": "0.9.10",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/documentcloud/backbone.git"
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "underscore",
|
||||
"version": "1.4.4",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/documentcloud/underscore.git"
|
||||
}
|
||||
}
|
||||
8
test/assets/package-existing-json/component.json
Normal file
8
test/assets/package-existing-json/component.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "sample-package",
|
||||
"version": "1.2.3",
|
||||
"main": ["sample.js"],
|
||||
"ignore": ["thingToIgnore"],
|
||||
"dependencies" : {},
|
||||
"custom": "A custom field"
|
||||
}
|
||||
1
test/assets/package-new/index.js
Normal file
1
test/assets/package-new/index.js
Normal file
@@ -0,0 +1 @@
|
||||
// An empty package
|
||||
154
test/init.js
Normal file
154
test/init.js
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user