Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

bower

Package Overview
Dependencies
Maintainers
2
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bower - npm Package Compare versions

Comparing version 0.10.0 to 1.0.0

.editorconfig

32

CHANGELOG.md
# Changelog
## 1.0.0 - 2013-07-23
Total rewrite of bower.
The list bellow highlights the most important stuff:
- Clear architecture and separation of concerns
- Much much faster
- `--json` output for all commands
- `--offline` usage for all commands, except `register`
- Proper `install` and `update` commands, similar to `npm` in behaviour
- Named endpoints when installing, e.g. `bower install backbone-amd=backbone#~1.0.0`
- New interactive conflict resolution strategy
- Prevent human errors when using `register`
- New `home` command, similar to `npm`
- New `cache list` command
- New `prune` command
- Many many general bug fixes
Non-backwards compatible changes:
- `json` from .bowerrc is no longer used
- Programmatic usage changed, specially the commands interface
Users upgrading from `bower-canary` should do a `bower cache clean`.
Users upgrading from `bower@~0.x.x` should remove the `~/.bower` folder manually since it's no longer used.
On Windows the folder is located in `AppData/bower`.
For a complete list of changes that this rewrite and release brings please read: https://github.com/bower/bower/wiki/Rewrite-state
## 0.10.0 - 2013-07-02

@@ -7,3 +37,3 @@

- __Change bower default folder from `components` to `bower_components`__ ([#434](https://github.com/bower/bower/issues/434))
- __Support semver pre-releases and builds ([#188](https://github.com/bower/bower/issues/188))
- __Support semver pre-releases and builds__ ([#188](https://github.com/bower/bower/issues/188))
- Use `Content-Type` and `Content-Disposition` to guess file types, such as zip files ([#454](https://github.com/bower/bower/pull/454))

@@ -10,0 +40,0 @@ - Fix bower failing silently when using an invalid version value in the bower.json file ([#439](https://github.com/bower/bower/issues/439))

76

lib/commands/help.js

@@ -1,52 +0,52 @@

// ==========================================
// BOWER: Help API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var path = require('path');
var fs = require('graceful-fs');
var Logger = require('bower-logger');
var cli = require('../util/cli');
var createError = require('../util/createError');
var events = require('events');
var nopt = require('nopt');
var _ = require('lodash');
function help(name) {
var json;
var logger = new Logger();
var template = require('../util/template');
var config = require('../core/config');
if (name) {
json = path.resolve(__dirname, '../../templates/json/help-' + name.replace(/\s+/g, '/') + '.json');
} else {
json = path.resolve(__dirname, '../../templates/json/help.json');
}
module.exports = function (name) {
var context = {};
var emitter = new events.EventEmitter;
var commands = require('../commands');
fs.exists(json, function (exists) {
if (!exists) {
return logger.emit('error', createError('Unknown command: ' + name, 'EUNKOWNCMD', {
command: name
}));
}
// Aliases
// At the moment we just have the ls, but we might have more
switch (name) {
case 'ls':
name = 'list';
break;
}
try {
json = require(json);
} catch (error) {
return logger.emit('error', error);
}
var validCommand = !!(name && commands[name]);
var templateName = validCommand ? 'help-' + name : 'help';
logger.emit('end', json);
});
if (!validCommand) context = {
commands: Object.keys(commands).sort().join(', ')
}
return logger;
}
_.extend(context, config);
// -------------------
template(templateName, context)
.on('data', emitter.emit.bind(emitter, 'end'));
help.line = function (argv) {
var options = help.options(argv);
return emitter;
return help(options.argv.remain.slice(1).join(' '));
};
module.exports.line = function (argv) {
var options = nopt({}, {}, argv);
var paths = options.argv.remain.slice(1);
return module.exports(paths[0]);
help.options = function (argv) {
return cli.readOptions(argv);
};
module.exports.completion = function (opts, cb) {
return cb(null, Object.keys(require('../commands')));
help.completion = function () {
// TODO
};
module.exports = help;

@@ -1,24 +0,16 @@

// ==========================================
// BOWER: Public Commands List
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
module.exports = {
'help': require('./help'),
'install': require('./install'),
'list': require('./list'),
'ls': require('./list'),
'uninstall': require('./uninstall'),
'update': require('./update'),
'link': require('./link'),
'lookup': require('./lookup'),
'info': require('./info'),
'init': require('./init'),
'register': require('./register'),
'search': require('./search'),
'cache-clean': require('./cache-clean'),
'completion': require('./completion')
cache: require('./cache'),
help: require('./help'),
home: require('./home'),
info: require('./info'),
init: require('./init'),
install: require('./install'),
link: require('./link'),
list: require('./list'),
lookup: require('./lookup'),
prune: require('./prune'),
register: require('./register'),
search: require('./search'),
update: require('./update'),
uninstall: require('./uninstall')
};

@@ -1,50 +0,80 @@

// ==========================================
// BOWER: Lookup API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Logger = require('bower-logger');
var PackageRepository = require('../core/PackageRepository');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var nopt = require('nopt');
function info(pkg, property, config) {
var repository;
var logger = new Logger();
var template = require('../util/template');
var source = require('../core/source');
var install = require('./install');
var help = require('./help');
config = mout.object.deepFillIn(config || {}, defaultConfig);
repository = new PackageRepository(config, logger);
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'] };
pkg = pkg.split('#');
pkg = {
name: pkg[0],
version: pkg[1]
};
module.exports = function (name) {
var emitter = new Emitter;
// If no version was specified, retrieve whole package info
if (!pkg.version) {
repository.versions(pkg.name)
.then(function (versions) {
logger.emit('end', {
name: pkg.name,
versions: versions
});
})
.fail(function (error) {
logger.emit('error', error);
});
// Otherwise fetch version and retrieve package meta
} else {
repository.fetch({
source: pkg.name,
target: pkg.version
})
.spread(function (canonicalDir, pkgMeta) {
pkgMeta = mout.object.filter(pkgMeta, function (value, key) {
return key.charAt(0) !== '_';
});
if (name) {
source.info(name, function (err, result) {
if (err) return emitter.emit('error', err);
emitter.emit('end', result);
});
}
// Retrieve specific property
if (property) {
pkgMeta = mout.object.get(pkgMeta, property);
}
return emitter;
};
logger.emit('end', pkgMeta);
})
.fail(function (error) {
logger.emit('error', error);
});
}
module.exports.line = function (argv) {
var emitter = new Emitter;
var options = nopt(optionTypes, shorthand, argv);
var names = options.argv.remain.slice(1);
return logger;
}
if (options.help || !names.length) return help('info');
// -------------------
module.exports(names[0])
.on('error', emitter.emit.bind(emitter, 'error'))
.on('end', function (data) {
template('info', data).on('data', emitter.emit.bind(emitter, 'end'));
});
info.line = function (argv) {
var options = info.options(argv);
var pkg = options.argv.remain[1];
var property = options.argv.remain[2];
return emitter;
if (!pkg) {
return null;
}
return info(pkg, property);
};
module.exports.completion = install.completion;
module.exports.completion.options = shorthand;
info.options = function (argv) {
return cli.readOptions(argv);
};
info.completion = function () {
// TODO:
};
module.exports = info;

@@ -1,150 +0,190 @@

// ==========================================
// BOWER: Init API
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var fs = require('graceful-fs');
var path = require('path');
var Q = require('q');
var inquirer = require('inquirer');
var Logger = require('bower-logger');
var endpointParser = require('bower-endpoint-parser');
var cli = require('../util/cli');
var Project = require('../core/Project');
var defaultConfig = require('../config');
function init(config) {
var project;
var logger = new Logger();
var path = require('path');
var fs = require('fs');
var util = require('util');
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
var nopt = require('nopt');
var promptly = require('promptly');
var _ = require('lodash');
// Start with existing JSON details
readJson(project, logger)
// Fill in defaults
.then(setDefaults.bind(null, config))
// Now prompt user to make changes
.then(promptUser)
// Set ignore based on the response
.spread(setIgnore)
// Set dependencies based on the response
.spread(setDependencies.bind(null, project))
// All done!
.spread(saveJson.bind(null, project))
.then(function (json) {
logger.emit('end', json);
})
.fail(function (error) {
logger.emit('error', error);
});
var help = require('./help');
var Manager = require('../core/manager');
var config = require('../core/config');
return logger;
}
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'] };
function readJson(project, logger) {
return project.hasJson()
.then(function (json) {
if (json) {
logger.warn('existing', 'The existing ' + path.basename(json) + ' file will be used and filled in');
}
var commonIgnore = ['**/.*', 'node_modules', 'components', 'bower_components', 'test', 'tests'];
return project.getJson();
});
}
var Init = function () {
Manager.call(this);
};
function saveJson(project, json) {
// Cleanup empty props, including objects and arrays
mout.object.forOwn(json, function (value, key) {
if (mout.lang.isEmpty(value)) {
delete json[key];
}
});
util.inherits(Init, Manager);
// Save json (true forces file creation)
return project.saveJson(true);
}
Init.prototype.getDependenciesJSON = function () {
var dependencies = Object.keys(this.dependencies);
var remaining = dependencies.length;
var json = {};
function setDefaults(config, json) {
var name;
dependencies.forEach(function (name) {
var pkg = this.dependencies[name][0];
// Name
if (!json.name) {
json.name = path.basename(config.cwd);
}
pkg.on('loadJSON', function () {
// TODO: use fetch endpoint here
json[pkg.name] = pkg.commit ? '*' : '~' + pkg.version;
remaining -= 1;
if (remaining === 0) {
this.manager.emit('loadDependencies', json);
}
}).loadJSON();
}, this);
// Version
if (!json.version) {
json.version = '0.0.0';
}
if (remaining === 0) {
this.emit('loadDependencies', json);
}
// Main
if (!json.main) {
// Remove '.js' from the end of the package name if it is there
name = path.basename(json.name, '.js');
return this;
};
if (fs.existsSync(path.join(config.cwd, 'index.js'))) {
json.main = 'index.js';
} else if (fs.existsSync(path.join(config.cwd, name + '.js'))) {
json.main = name + '.js';
}
}
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;
}
};
return json;
}
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);
};
function promptUser(json) {
var deferred = Q.defer();
Init.prototype.prompts = function (dependencies) {
var main = this.json.main || this.getMain(this.json.name) || '';
var questions = [
{
'name': 'name',
'message': 'name',
'default': json.name,
'type': 'input'
},
{
'name': 'version',
'message': 'version',
'default': json.version,
'type': 'input'
},
{
'name': 'main',
'message': 'main file',
'default': json.main,
'type': 'input'
},
{
'name': 'dependencies',
'message': 'set currently installed components as dependencies?',
'default': !mout.object.size(json.dependencies) && !mout.object.size(json.devDependencies),
'type': 'confirm'
},
{
'name': 'ignore',
'message': 'add commonly ignored files to ignore list?',
'default': true,
'type': 'confirm'
}
];
var questions = _.compact([
{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},
_.size(dependencies) ? {key: 'dependencies', prompt: 'add current components as dependencies? (y/n)', value: dependencies, yesno: true} : null,
{key: 'ignore', prompt: 'add commonly ignored files to ignore list? (y/n)', value: commonIgnore, yesno: true}
]);
var index = 0;
var question = questions[index];
inquirer.prompt(questions, function (answers) {
json.name = answers.name;
json.version = answers.version;
json.main = answers.main;
var cb = function (err, value) {
if (question.yesno) {
if (value) {
this.json[question.key] = question.value;
}
} else if (value) {
this.json[question.key] = value;
return deferred.resolve([json, answers]);
});
return deferred.promise;
}
function setIgnore(json, answers) {
if (answers.ignore) {
json.ignore = mout.array.combine(json.ignore || [], [
'**/.*',
'node_modules',
'bower_components',
'test',
'tests'
]);
}
index += 1;
if (index < questions.length) {
question = questions[index];
this.showPrompt(question, cb);
} else {
this.emit('prompts');
}
}.bind(this);
this.showPrompt(question, cb);
};
return [json, answers];
}
Init.prototype.save = function (data) {
fs.writeFileSync(path.join(this.cwd, config.json), JSON.stringify(data, null, 2));
};
function setDependencies(project, json, answers) {
if (answers.dependencies) {
return project.getTree()
.spread(function (tree, flattened, extraneous) {
if (extraneous.length) {
json.dependencies = {};
module.exports = function () {
var init = new Init();
// Add extraneous as dependencies
// TODO: The final expanded source is used instead of the original source
// While this the most correct it might be confusing to users
extraneous.forEach(function (extra) {
var jsonEndpoint = endpointParser.decomposed2json(extra.endpoint);
mout.object.mixIn(json.dependencies, jsonEndpoint);
});
}
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 [json, answers];
});
}
return init;
};
return [json, answers];
}
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();
init.line = function () {
return init();
};
module.exports.completion = function (opts, cb) {
var word = opts.word;
init.options = function (argv) {
return cli.readOptions(argv);
};
// completing options?
if (word.charAt(0) === '-') {
return cb(null, Object.keys(optionTypes).map(function (option) {
return '--' + option;
}));
}
init.completion = function () {
// TODO:
};
module.exports = init;

@@ -1,82 +0,51 @@

// ==========================================
// BOWER: Install API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Logger = require('bower-logger');
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var nopt = require('nopt');
var fs = require('fs');
var path = require('path');
function install(endpoints, options, config) {
var project;
var logger = new Logger();
var Manager = require('../core/manager');
var config = require('../core/config');
var source = require('../core/source');
var save = require('../util/save');
var help = require('./help');
options = options || {};
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
var optionTypes = { help: Boolean, save: Boolean, 'save-dev': Boolean, force: Boolean, 'force-latest': Boolean, production: Boolean };
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'D': ['--save-dev'], 'f': ['--force'], 'F': ['--force-latest'], 'p': ['--production'] };
// If endpoints is an empty array, null them
if (endpoints && !endpoints.length) {
endpoints = null;
}
module.exports = function (paths, options) {
options = options || {};
project.install(endpoints, options)
.then(function (installed) {
logger.emit('end', installed);
})
.fail(function (error) {
logger.emit('error', error);
});
var emitter = new Emitter;
var manager = new Manager(paths, {
force: options.force,
forceLatest: options['force-latest'],
production: options.production
});
return logger;
}
manager
.on('data', emitter.emit.bind(emitter, 'data'))
.on('warn', emitter.emit.bind(emitter, 'warn'))
.on('error', emitter.emit.bind(emitter, 'error'))
.on('resolve', function (resolved) {
// Handle save/save-dev
if (resolved && (options.save || options['save-dev'])) {
save(manager, paths, !options.save, emitter.emit.bind(emitter, 'end'));
} else {
emitter.emit('end');
}
})
.resolve();
// -------------------
return emitter;
install.line = function (argv) {
var options = install.options(argv);
return install(options.argv.remain.slice(1), options);
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
var paths = options.argv.remain.slice(1);
if (options.help) return help('install');
return module.exports(paths, options);
install.options = function (argv) {
return cli.readOptions({
'force-latest': { type: Boolean, shorthand: 'F'},
'production': { type: Boolean, shorthand: 'p' },
'save': { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
}, argv);
};
module.exports.completion = function (opts, cb) {
var cache = path.join(config.completion, 'install.json');
var done = function done(err, results) {
if (err) return cb(err);
var names = results.map(function (pkg) {
return pkg.name;
});
return cb(null, names);
};
fs.readFile(cache, function (err, body) {
if (!err) return done(null, JSON.parse(body));
// expected error, do the first request and cache the results
source.all(function (err, results) {
if (err) return cb(err);
fs.writeFile(cache, JSON.stringify(results, null, 2), function (err) {
done(err, results);
});
});
});
install.completion = function () {
// TODO:
};
module.exports.completion.options = shorthand;
module.exports = install;

@@ -1,121 +0,126 @@

// ==========================================
// BOWER: Link API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var fs = require('graceful-fs');
var path = require('path');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var mout = require('mout');
var Q = require('q');
var Logger = require('bower-logger');
var Project = require('../core/Project');
var createError = require('../util/createError');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var nopt = require('nopt');
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
function linkSelf(config) {
var project;
var logger = new Logger();
var Manager = require('../core/manager');
var help = require('./help');
var template = require('../util/template');
var config = require('../core/config');
var isRepo = require('../util/is-repo');
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'] };
project.getJson()
.then(function (json) {
var src = config.cwd;
var dst = path.join(config.storage.links, json.name);
function linkSelf(emitter) {
var manager = new Manager;
// Delete previous link if any
return Q.nfcall(rimraf, dst)
// Link globally
.then(function () {
return createLink(src, dst);
})
.then(function () {
logger.emit('end', {
src: src,
dst: dst
});
});
})
.fail(function (error) {
logger.emit('error', error);
});
manager
.on('error', emitter.emit.bind('error'))
.once('loadJSON', function () {
var destPath = path.join(config.links, manager.name);
var srcPath = process.cwd();
deleteLink(destPath, function (err) {
if (err) return emitter.emit('error', err);
createLink(srcPath, destPath, function (err) {
if (err) return emitter.emit('error', err);
template('link', { src: srcPath, dest: destPath })
.on('data', emitter.emit.bind(emitter, 'end'));
});
});
}).loadJSON();
return logger;
}
function linkTo(name, emitter) {
var destPath = path.join(process.cwd(), config.directory, name);
var srcPath = path.join(config.links, name);
function linkTo(name, localName, config) {
var src;
var dst;
var logger = new Logger();
deleteLink(destPath, function (err) {
if (err) return emitter.emit('error', err);
config = mout.object.deepFillIn(config || {}, defaultConfig);
createLink(srcPath, destPath, function (err) {
if (err) return emitter.emit('error', err);
localName = localName || name;
src = path.join(config.storage.links, name);
dst = path.join(process.cwd(), config.directory, localName);
template('link', { src: srcPath, dest: destPath })
.on('data', emitter.emit.bind(emitter, 'end'));
// Delete destination folder if any
Q.nfcall(rimraf, dst)
// Link locally
.then(function () {
return createLink(src, dst);
})
.then(function () {
logger.emit('end', {
src: src,
dst: dst
});
})
.fail(function (error) {
logger.emit('error', error);
});
});
}
function deleteLink(dest, callback) {
// Delete symlink if already present
// Beware that if the target is a git repo, we can't proceed
isRepo(dest, function (is) {
if (is) return callback(new Error(dest + ' is a local repository, please remove it manually'));
fs.lstat(dest, function (err) {
if (!err || err.code !== 'ENOENT') rimraf(dest, callback);
else callback();
});
});
return logger;
}
function createLink(src, dest, callback) {
var destDir = path.dirname(dest);
function createLink(src, dst) {
var dstDir = path.dirname(dst);
// Create directory
mkdirp(destDir, function (err) {
if (err) return callback(err);
// Create directory
return Q.nfcall(mkdirp, dstDir)
// Check if source exists
.then(function () {
return Q.nfcall(fs.lstat, src)
.fail(function (error) {
if (error.code === 'ENOENT') {
throw createError('Failed to create link to ' + path.basename(src), 'ENOENT', {
details: src + ' doest not exists or points to a non-existent package'
});
}
fs.lstat(src, function (err) {
if (err && err.code === 'ENOENT') {
return callback(new Error('Attempting to link an unknown package: ' + path.basename(src)));
}
// Create symlink
fs.symlink(src, dest, 'dir', function (err) {
callback(err);
});
throw error;
});
})
// Create symlink
.then(function () {
return Q.nfcall(fs.symlink, src, dst, 'dir');
});
});
}
module.exports = function (name) {
var emitter = new Emitter;
// -------------------
if (!name) linkSelf(emitter);
else linkTo(name, emitter);
return emitter;
var link = {
linkTo: linkTo,
linkSelf: linkSelf
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
var name = options.argv.remain[1];
link.line = function (argv) {
var options = link.options(argv);
var name = options.argv.remain[1];
var localName = options.argv.remain[2];
if (options.help) return help('link');
return module.exports(name);
if (name) {
return linkTo(name, localName);
}
return linkSelf();
};
module.exports.completion = function (opts, cb) {
fs.readdir(config.links, function (err, dirs) {
// ignore ENOENT, ~/.bower/links not created yet
if (err && err.code === 'ENOENT') return cb(null, []);
cb(err, dirs);
});
link.options = function (argv) {
return cli.readOptions(argv);
};
module.exports.completion.options = shorthand;
link.completion = function () {
// TODO:
};
module.exports = link;

@@ -1,245 +0,120 @@

// ==========================================
// BOWER: List API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var path = require('path');
var mout = require('mout');
var semver = require('semver');
var Q = require('q');
var Logger = require('bower-logger');
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var archy = require('archy');
var nopt = require('nopt');
var path = require('path');
var _ = require('lodash');
function list(options, config) {
var project;
var logger = new Logger();
var template = require('../util/template');
var Manager = require('../core/manager');
var Package = require('../core/package');
var config = require('../core/config');
var help = require('./help');
var fallback = require('../util/fallback');
options = options || {};
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
var shorthand = { 'h': ['--help'], 'o': ['--offline'] };
var optionTypes = { help: Boolean, paths: Boolean, map: Boolean, offline: Boolean, sources: Boolean };
project.getTree()
.spread(function (tree, flattened, extraneous) {
if (options.paths) {
return logger.emit('end', paths(flattened));
}
var getTree = function (packages, subPackages, result) {
result = result || {};
if (config.offline) {
return logger.emit('end', normal(tree, extraneous));
}
_.each(subPackages || packages, function (pkg) {
result[pkg.name] = {};
Object.keys(pkg.json.dependencies || {}).forEach(function (name) {
result[pkg.name][name] = {};
return checkVersions(project, tree, logger)
.then(function () {
logger.emit('end', normal(tree, extraneous));
});
})
.fail(function (error) {
logger.emit('error', error);
});
var subPackages = {};
logger.json = !!options.paths;
Object.keys(pkg.json.dependencies || {}).forEach(function (name) {
subPackages[name] = packages[name] || new Package(name, null);
});
return logger;
}
getTree(packages, subPackages, result[pkg.name]);
});
function checkVersions(project, tree, logger) {
var promises;
var nodes = [];
var repository = project.getPackageRepository();
return result;
};
// Gather all nodes
project.walkTree(tree, function (node) {
nodes.push(node);
}, true);
var generatePath = function (name, main) {
if (typeof main === 'string') {
return path.join(config.directory, name, main);
} else if (_.isArray(main)) {
main = main.map(function (main) { return generatePath(name, main); });
return main.length === 1 ? main[0] : main;
}
};
if (nodes.length) {
logger.info('check-new', 'Checking for new versions of the project dependencies..');
}
var mainTypes = ['main', 'scripts', 'styles', 'templates', 'images'];
// Check for new versions for each node
promises = nodes.map(function (node) {
var target = node.endpoint.target;
var buildSource = function (pkg, shallow) {
var result = {};
return repository.versions(node.endpoint.source)
.then(function (versions) {
node.versions = versions;
if (pkg) {
mainTypes.forEach(function (type) {
if (pkg.json[type]) result[type] = generatePath(pkg.name, pkg.json[type]);
// Do not check if node's target is not a valid semver one
if (versions.length && semver.validRange(target)) {
node.update = {
target: semver.maxSatisfying(versions, target),
latest: semver.maxSatisfying(versions, '*')
};
}
});
});
}
if (shallow) {
result.main = getMain(result) || generatePath(pkg.name, '');
}
// Set the versions also for the root node
tree.versions = [];
return result;
};
return Q.all(promises);
}
var getMain = function (source) {
for (var i = 0, len = mainTypes.length; i < len; i += 1) {
var type = mainTypes[i];
if (source[type]) {
return source[type];
}
}
};
function paths(flattened) {
var ret = {};
var shallowTree = function (packages, tree) {
var result = {};
mout.object.forOwn(flattened, function (pkg, name) {
if (!pkg.missing) {
ret[name] = path.normalize(pkg.canonicalDir + '/' + (pkg.pkgMeta.main || ''));
}
});
Object.keys(tree).forEach(function (packageName) {
result[packageName] = buildSource(packages[packageName], true).main;
});
return ret;
}
return result;
};
function normal(tree, extraneous) {
// Merge extraneous as root dependencies
// but signal it with a flag
extraneous.forEach(function (decEndpoint) {
decEndpoint.extraneous = true;
tree.dependencies[decEndpoint.endpoint.name] = decEndpoint;
});
var deepTree = function (packages, tree) {
return tree;
}
var result = {};
// -------------------
Object.keys(tree).forEach(function (packageName) {
result[packageName] = {};
result[packageName].source = buildSource(packages[packageName]);
if (Object.keys(tree[packageName]).length) {
result[packageName].dependencies = deepTree(packages, tree[packageName]);
}
});
return result;
list.line = function (argv) {
var options = list.options(argv);
return list(options);
};
var getNodes = function (packages, tree) {
return Object.keys(tree).map(function (key) {
var version = packages[key] ? packages[key].version || '' : null;
var upgrade;
if (version && packages[key].tags.indexOf(version)) {
upgrade = packages[key].tags[0];
}
if (Object.keys(tree[key]).length) {
return {
label: template('tree-branch', { 'package': key, version: version, upgrade: upgrade }, true),
nodes: getNodes(packages, tree[key])
};
} else {
return template('tree-branch', { 'package': key, version: version, upgrade: upgrade }, true);
}
});
list.options = function (argv) {
return cli.readOptions({
'paths': { type: Boolean, shorthand: 'p' }
}, argv);
};
var getDependencySrcs = function (list) {
var srcs = [];
var dependency, main;
for (var name in list) {
dependency = list[name];
main = dependency.source && getMain(dependency.source);
if (dependency.dependencies) {
var depSrcs = getDependencySrcs(dependency.dependencies);
srcs.push.apply(srcs, depSrcs);
}
// add main sources to srcs
if (main) {
if (Array.isArray(main)) {
srcs.push.apply(srcs, main);
} else {
srcs.push(main);
}
}
}
return srcs;
list.completion = function () {
// TODO:
};
var organizeSources = function (tree) {
// flat source filepaths
var srcs = getDependencySrcs(tree);
// remove duplicates, organize by file extension
var sources = {};
srcs.forEach(function (src) {
var ext = path.extname(src);
sources[ext] = sources[ext] || [];
if (sources[ext].indexOf(src) === -1) {
sources[ext].push(src);
}
});
return sources;
};
module.exports = function (options) {
var manager = new Manager;
var emitter = new Emitter;
options = options || {};
if (options.sources) {
options.map = true;
}
var emitOut = function (obj) {
// make JSON pretty if started from command line
var output = options.argv ? JSON.stringify(obj, null, 2) : obj;
emitter.emit('data', output);
};
manager
.on('data', emitter.emit.bind(emitter, 'data'))
.on('error', emitter.emit.bind(emitter, 'error'))
.on('list', function (packages) {
var tree = getTree(packages);
var rootLabel;
if (!options.paths && !options.map) {
return fallback(process.cwd(), [config.json, 'bower.json', 'component.json'], function (name) {
try {
if (name == null) throw new Error('No json');
rootLabel = require(path.join(process.cwd(), name)).name;
} catch (e) {
rootLabel = path.basename(process.cwd());
}
emitter.emit('data', archy({
label: rootLabel,
nodes: getNodes(packages, tree)
}));
});
}
tree = options.paths ? shallowTree(packages, tree) : deepTree(packages, tree);
if (options.sources) {
// with map, organize it and emit
var sources = organizeSources(tree);
emitOut(sources);
} else {
emitOut(tree);
}
})
.list(options);
return emitter;
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
if (options.help) return help('list');
return module.exports(options);
};
module.exports.completion = function (opts, cb) {
if (!/^-/.test(opts.word)) return cb(null, []);
var results = Object.keys(optionTypes).map(function (option) {
return '--' + option;
});
cb(null, results);
};
module.exports.completion.options = shorthand;
module.exports = list;

@@ -1,64 +0,54 @@

// ==========================================
// BOWER: Lookup API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Q = require('q');
var Logger = require('bower-logger');
var RegistryClient = require('bower-registry-client');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var nopt = require('nopt');
function lookup(name, config) {
var registryClient;
var logger = new Logger();
var template = require('../util/template');
var source = require('../core/source');
var install = require('./install');
var help = require('./help');
config = mout.object.deepFillIn(config || {}, defaultConfig);
config.cache = config.storage.registry;
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'] };
registryClient = new RegistryClient(config, logger);
module.exports = function (name) {
var emitter = new Emitter;
Q.nfcall(registryClient.lookup.bind(registryClient), name)
.then(function (entry) {
// TODO: Handle entry.type.. for now it's only 'alias'
// When we got published packages, this needs to be adjusted
logger.emit('end', !entry ? null : {
name: name,
url: entry && entry.url
});
})
.fail(function (error) {
logger.emit('error', error);
});
source.lookup(name, function (err, url) {
if (err) {
source.search(name, function (err, packages) {
if (packages.length) {
template('suggestions', { packages: packages, name: name })
.on('data', function (data) {
emitter.emit('data', data);
emitter.emit('end');
});
} else {
template('warning-missing', {name: name})
.on('data', function (data) {
emitter.emit('data', data);
emitter.emit('end');
});
}
});
} else {
var result = { name: name, url: url };
emitter.emit('package', result);
return logger;
}
template('lookup', result)
.on('data', function (data) {
emitter.emit('data', data);
emitter.emit('end');
});
// -------------------
lookup.line = function (argv) {
var options = lookup.options(argv);
var name = options.argv.remain[1];
if (!name) {
return null;
}
});
return emitter;
return lookup(name);
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
var names = options.argv.remain.slice(1);
lookup.options = function (argv) {
return cli.readOptions(argv);
};
if (options.help || !names.length) return help('lookup');
return module.exports(names[0]);
lookup.completion = function () {
// TODO:
};
module.exports.completion = install.completion;
module.exports.completion.options = shorthand;
module.exports = lookup;

@@ -1,66 +0,127 @@

// ==========================================
// BOWER: Lookup API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Q = require('q');
var promptly = require('promptly');
var PackageRepository = require('../core/PackageRepository');
var Logger = require('bower-logger');
var cli = require('../util/cli');
var createError = require('../util/createError');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var nopt = require('nopt');
var readline = require('readline');
function register(name, url, config) {
var repository;
var registryClient;
var logger = new Logger();
var force;
var template = require('../util/template');
var source = require('../core/source');
var help = require('./help');
config = mout.object.deepFillIn(config || {}, defaultConfig);
force = config.force;
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'], '-s': ['--silent'] };
// Bypass any cache
config.offline = false;
config.force = true;
var register = function (name, url, emitter) {
source.register(name, url, function (err) {
if (err) return emitter.emit('error', err);
// Trim name
name = name.trim();
template('register', {name: name, url: url})
.on('data', emitter.emit.bind(emitter, 'data'));
});
};
process.nextTick(function () {
// Verify name
// TODO: Verify with the new spec regexp?
if (!name) {
return logger.emit('error', createError('Please type a name', 'EINVNAME'));
}
module.exports = function (name, url, options) {
var emitter = new Emitter;
// Convert URLs
url = convertUrl(url, logger);
if (options.silent) register(name, url, emitter);
else {
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
// Ensure the URL starts with git://
// TODO: After the registry server is rewritten this might change
if (!mout.string.startsWith(url, 'git://')) {
return logger.emit('error', createError('The registry only accepts URLs starting with git://', 'EINVFORMAT'));
}
console.log('Registering a package will make it visible and installable via the registry.');
rl.question('Proceed (y/n)? ', function (res) {
rl.close();
// Attempt to resolve the package referenced by the URL to ensure
// everything is ok before registering
repository = new PackageRepository(config, logger);
repository.fetch({ name: name, source: url, target: '*' })
.then(function () {
// If non interactive or user forced, bypass confirmation
if (!config.interactive || force) {
return true;
}
res = res.toLowerCase();
// Confirm if the user really wants to register
return Q.nfcall(promptly.confirm, 'Registering a package will make it visible and installable via the registry, continue? (y/n)');
})
.then(function (result) {
// If user response was negative, abort
if (!result) {
return;
}
if (res === 'y' || res === 'yes') register(name, url, emitter);
// Register
registryClient = repository.getRegistryClient();
logger.action('register', url, {
name: name,
url: url
});
return Q.nfcall(registryClient.register.bind(registryClient), name, url);
})
.then(function (result) {
logger.emit('end', result);
})
.fail(function (error) {
logger.emit('error', error);
});
});
}
return emitter;
};
return logger;
}
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
var args = options.argv.remain.slice(1);
function convertUrl(url, logger) {
var matches;
var newUrl;
if (options.help || args.length !== 2) return help('register');
return module.exports(args[0], args[1], options);
// Convert GitHub ssh urls
matches = url.match(/^git@github\.com:([^\/]+\/[^\/]+)\.git$/);
if (matches) {
newUrl = 'git://github.com/' + matches[1] + '.git';
logger.warn('convert', 'Converted ' + url + ' to ' + newUrl);
return newUrl;
}
// Convert GitHub https urls
matches = url.match(/^https?:\/\/github\.com\/([^\/]+\/[^\/]+)\.git$/);
if (matches) {
newUrl = 'git://github.com/' + matches[1] + '.git';
logger.warn('convert', 'Converted ' + url + ' to ' + newUrl);
return newUrl;
}
return url;
}
// -------------------
register.line = function (argv) {
var options = register.options(argv);
var name = options.argv.remain[1];
var url = options.argv.remain[2];
if (!name || !url) {
return null;
}
return register(name, url);
};
module.exports.completion = function (opts, cb) {
var word = opts.word;
register.options = function (argv) {
return cli.readOptions(argv);
};
// completing options?
if (word.charAt(0) === '-') {
return cb(null, Object.keys(optionTypes).map(function (option) {
return '--' + option;
}));
}
register.completion = function () {
// TODO:
};
module.exports = register;

@@ -1,61 +0,52 @@

// ==========================================
// BOWER: Lookup API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Q = require('q');
var Logger = require('bower-logger');
var RegistryClient = require('bower-registry-client');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var nopt = require('nopt');
function search(name, config) {
var registryClient;
var promise;
var logger = new Logger();
var template = require('../util/template');
var source = require('../core/source');
var install = require('./install');
var help = require('./help');
config = mout.object.deepFillIn(config || {}, defaultConfig);
config.cache = config.storage.registry;
var optionTypes = { help: Boolean };
var shorthand = { 'h': ['--help'] };
registryClient = new RegistryClient(config, logger);
module.exports = function (name) {
var emitter = new Emitter;
// If no name was specified, list all packages
if (!name) {
promise = Q.nfcall(registryClient.list.bind(registryClient));
// Otherwise search it
} else {
promise = Q.nfcall(registryClient.search.bind(registryClient), name);
}
var callback = function (err, results) {
if (err) return emitter.emit('error', err);
promise
.then(function (results) {
logger.emit('end', results);
})
.fail(function (error) {
logger.emit('error', error);
});
emitter.emit('packages', results);
return logger;
}
if (results.length) {
template('search', {results: results})
.on('data', function (data) {
emitter.emit('data', data);
emitter.emit('end');
});
} else {
template('search-empty', {results: results})
.on('data', function (data) {
emitter.emit('data', data);
emitter.emit('end');
});
}
};
// -------------------
if (name) {
source.search(name, callback);
} else {
source.all(callback);
}
search.line = function (argv) {
var options = search.options(argv);
return search(options.argv.remain.slice(1).join(' '), options);
};
return emitter;
search.options = function (argv) {
return cli.readOptions(argv);
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
var names = options.argv.remain.slice(1);
if (options.help) return help('search');
return module.exports(names[0]);
search.completion = function () {
// TODO:
};
module.exports.completion = install.completion;
module.exports.completion.options = shorthand;
module.exports = search;

@@ -1,206 +0,55 @@

// ==========================================
// BOWER: Uninstall API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Logger = require('bower-logger');
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var async = require('async');
var nopt = require('nopt');
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
function uninstall(names, options, config) {
var project;
var logger = new Logger();
var template = require('../util/template');
var Manager = require('../core/manager');
var config = require('../core/config');
var help = require('./help');
options = options || {};
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
var optionTypes = { help: Boolean, force: Boolean, save: Boolean };
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'D': ['--save-dev'], 'f': ['--force'] };
module.exports = function (names, options) {
var packages, uninstallables, packagesCount = {};
var emitter = new Emitter;
var manager = new Manager;
var jsonDeps;
var newLine;
options = options || {};
manager.on('data', emitter.emit.bind(emitter, 'data'));
manager.on('error', emitter.emit.bind(emitter, 'error'));
var resolveLocal = function () {
jsonDeps = manager.json.dependencies || {};
packages = _.flatten(_.values(manager.dependencies));
uninstallables = packages.filter(function (pkg) {
return _.include(names, pkg.name);
});
async.forEach(packages, function (pkg, next) {
pkg.once('loadJSON', next).loadJSON();
}, function () {
if (showWarnings(options.force) && !options.force) return;
expandUninstallabes(options.force);
uninstall();
});
};
var showWarnings = function (force) {
var foundConflicts = false;
packages.forEach(function (pkg) {
if (!pkg.json.dependencies) return;
if (containsPkg(uninstallables, pkg)) return;
var conflicts = _.intersection(
Object.keys(pkg.json.dependencies),
_.pluck(uninstallables, 'name')
);
if (conflicts.length) {
foundConflicts = true;
if (!force) {
conflicts.forEach(function (conflictName) {
emitter.emit('data', template('warning-uninstall', { packageName: pkg.name, conflictName: conflictName }, true));
});
}
}
});
if (foundConflicts && !force) {
emitter.emit('data', template('warn', { message: 'To proceed, run uninstall with the --force flag'}, true));
// If names is an empty array, null them
if (names && !names.length) {
names = null;
}
return foundConflicts;
};
var expandUninstallabes = function (force) {
var x,
pkg,
forcedUninstallables = {};
// Direct JSON deps have a count of 1
for (var key in jsonDeps) {
packagesCount[key] = 1;
}
// Count all packages
count(packages, packagesCount);
if (force) {
uninstallables.forEach(function (pkg) {
forcedUninstallables[pkg.name] = true;
});
}
// Expand the uninstallables deps and nested deps
// Also update the count accordingly
for (x = uninstallables.length - 1; x >= 0; x -= 1) {
parseUninstallableDeps(uninstallables[x]);
}
// Foreach uninstallable, check if it is really to be removed by reading the final count
// If the final count is greater than 0, then it is a shared dep
// In that case, we remove it from the uninstallables unless it's forced to be uninstalled
for (x = uninstallables.length - 1; x >= 0; x -= 1) {
pkg = uninstallables[x];
if (packagesCount[pkg.name] > 0 && !forcedUninstallables[pkg.name]) uninstallables.splice(x, 1);
}
};
var count = function (packages, counts, nested) {
packages.forEach(function (pkg) {
counts[pkg.name] = (counts[pkg.name] || 0);
if (nested) counts[pkg.name] += 1;
if (pkg.json.dependencies) {
for (var key in pkg.json.dependencies) {
count(manager.dependencies[key], counts, true);
}
}
project.uninstall(names, options)
.then(function (removed) {
logger.emit('end', removed);
})
.fail(function (error) {
logger.emit('error', error);
});
};
var parseUninstallableDeps = function (pkg) {
if (!containsPkg(uninstallables, pkg)) uninstallables.push(pkg);
packagesCount[pkg.name] -= 1;
return logger;
}
if (pkg.json.dependencies) {
for (var key in pkg.json.dependencies) {
parseUninstallableDeps(manager.dependencies[key][0]);
}
}
};
// -------------------
var containsPkg = function (packages, pkg) {
for (var x = packages.length - 1; x >= 0; x -= 1) {
if (packages[x].name === pkg.name) return true;
}
uninstall.line = function (argv) {
var options = uninstall.options(argv);
var names = options.argv.remain.slice(1);
return false;
};
var uninstall = function () {
async.forEach(uninstallables, function (pkg, next) {
pkg.on('uninstall', function () {
emitter.emit('package', pkg);
next();
}).uninstall();
}, function () {
// Finally save
if (options.save || options['save-dev']) save(!options.save);
emitter.emit('end');
});
};
var save = function (dev) {
var key = dev ? 'devDependencies' : 'dependencies';
var contents;
if (manager.json[key]) {
names.forEach(function (name) {
delete manager.json[key][name];
});
contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
fs.writeFileSync(path.join(manager.cwd, config.json), contents);
if (!names.length) {
return null;
}
};
manager.on('loadJSON', function (hasNewLine) {
newLine = hasNewLine;
manager.on('resolveLocal', resolveLocal).resolveLocal();
}).loadJSON();
return emitter;
return uninstall(names, options);
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
var names = options.argv.remain.slice(1);
if (options.help || !names.length) return help('uninstall');
return module.exports(names, options);
uninstall.options = function (argv) {
return cli.readOptions({
'save': { type: Boolean, shorthand: 'S' },
'save-dev': { type: Boolean, shorthand: 'D' }
}, argv);
};
module.exports.completion = function (opts, cb) {
var word = opts.word;
// completing options?
if (opts.words[0] === 'uninstall' && word.charAt(0) === '-') {
return cb(null, Object.keys(optionTypes).map(function (option) {
return '--' + option;
}));
}
fs.readdir(config.directory, function (err, dirs) {
// ignore ENOENT, ./bower_components not created yet
if (err && err.code === 'ENOENT') return cb(null, []);
cb(err, dirs);
});
uninstall.completion = function () {
// TODO:
};
module.exports.completion.options = shorthand;
module.exports = uninstall;

@@ -1,110 +0,49 @@

// ==========================================
// BOWER: Update API
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var mout = require('mout');
var Logger = require('bower-logger');
var Project = require('../core/Project');
var cli = require('../util/cli');
var defaultConfig = require('../config');
var Emitter = require('events').EventEmitter;
var async = require('async');
var nopt = require('nopt');
var _ = require('lodash');
function update(names, options, config) {
var project;
var logger = new Logger();
var Manager = require('../core/manager');
var help = require('./help');
var uninstall = require('./uninstall');
var save = require('../util/save');
options = options || {};
config = mout.object.deepFillIn(config || {}, defaultConfig);
project = new Project(config, logger);
var optionTypes = { help: Boolean, save: Boolean, force: Boolean, 'force-latest': Boolean };
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'f': ['--force'], 'F': ['--force-latest'] };
module.exports = function (names, options) {
options = options || {};
var emitter = new Emitter;
var manager = new Manager([], {
force: options.force,
forceLatest: options['force-latest']
});
manager.on('data', emitter.emit.bind(emitter, 'data'));
manager.on('error', emitter.emit.bind(emitter, 'error'));
var install = function (err, array) {
var mappings = {},
endpoints = [],
name,
info,
length,
x;
length = names.length;
if (length) {
for (x = 0; x < length; x += 1) {
name = names[x];
info = _.find(array, function (info) { return info.name === name; });
if (!info) {
return emitter.emit('error', new Error('Package ' + name + ' is not installed'));
}
endpoints.push(info.endpoint);
mappings[info.endpoint] = info.name;
}
} else {
array.forEach(function (info) {
endpoints.push(info.endpoint);
mappings[info.endpoint] = info.name;
});
// If names is an empty array, null them
if (names && !names.length) {
names = null;
}
options.endpointNames = mappings;
project.update(names, options)
.then(function (installed) {
logger.emit('end', installed);
})
.fail(function (error) {
logger.emit('error', error);
});
// By default the manager will guess the name of the package from the url
// But this leads to problems when the package name does not match the one in the url
// So the manager now has an option (endpointNames) to deal with this
manager = new Manager(endpoints, options);
manager
.on('data', emitter.emit.bind(emitter, 'data'))
.on('warn', emitter.emit.bind(emitter, 'warn'))
.on('error', emitter.emit.bind(emitter, 'error'))
.on('resolve', function (resolved) {
// Handle save
if (resolved && options.save) save(manager, null, false, emitter.emit.bind(emitter, 'end'));
else emitter.emit('end');
})
.resolve();
};
return logger;
}
manager.once('resolveLocal', function () {
async.map(_.values(manager.dependencies), function (pkgs, next) {
var pkg = pkgs[0];
pkg.once('loadJSON', function () {
var endpointInfo = pkg.readEndpoint();
if (!endpointInfo) return next();
// -------------------
// Add tag only if the endpoint is a repository
var endpoint = endpointInfo.endpoint;
var json = pkg.json;
if (!json.commit && (endpointInfo.type === 'git' || endpointInfo.type === 'local-repo')) {
endpoint += '#' + ((!names || names.indexOf(pkg.name) > -1) ? '~' : '') + pkg.version;
}
update.line = function (argv) {
var options = update.options(argv);
return update(options.argv.remain.slice(1), options);
};
next(null, { name: pkg.name, endpoint: endpoint });
}).loadJSON();
}, install);
}).resolveLocal();
return emitter;
update.options = function (argv) {
return cli.readOptions({
'force-latest': { type: Boolean, shorthand: 'F' },
'production': { type: Boolean, shorthand: 'p' }
}, argv);
};
module.exports.line = function (argv) {
var options = nopt(optionTypes, shorthand, argv);
if (options.help) return help('update');
var paths = options.argv.remain.slice(1);
return module.exports(paths, options);
update.completion = function () {
// TODO:
};
module.exports.completion = uninstall.completion;
module.exports.completion.options = shorthand;
module.exports = update;

@@ -1,20 +0,39 @@

// ==========================================
// BOWER: Public API Definition
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
var abbrev = require('abbrev');
var mout = require('mout');
var commands = require('./commands');
var PackageRepository = require('./core/PackageRepository');
var abbreviations = abbrev(Object.keys(commands));
var abbreviations = abbrev(expandNames(commands));
abbreviations.i = 'install';
abbreviations.rm = 'uninstall';
function expandNames(obj, prefix, stack) {
prefix = prefix || '';
stack = stack || [];
mout.object.forOwn(obj, function (value, name) {
name = prefix + name;
stack.push(name);
if (typeof value === 'object' && !value.line) {
expandNames(value, name + ' ', stack);
}
});
return stack;
}
function clearRuntimeCache() {
// Note that in edge cases, some architecture components instance's
// in-memory cache might be skipped.
// If that's a problem, you should create and fresh instances instead.
PackageRepository.clearRuntimeCache();
}
module.exports = {
commands: commands,
abbreviations: abbreviations,
config: require('./core/config')
commands: commands,
config: require('./config'),
abbreviations: abbreviations,
reset: clearRuntimeCache
};

@@ -1,41 +0,45 @@

// ==========================================
// BOWER: Hogan Renderer w/ template cache
// ==========================================
// Copyright 2012 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
require('colors');
var path = require('path');
var fs = require('graceful-fs');
var Handlebars = require('handlebars');
var mout = require('mout');
var helpers = require('../../templates/helpers');
var events = require('events');
var hogan = require('hogan.js');
var path = require('path');
var fs = require('fs');
var templatesDir = path.resolve(__dirname, '../../templates');
var cache = {};
require('../util/hogan-colors');
// Register helpers
mout.object.forOwn(helpers, function (register) {
register(Handlebars);
});
var templates = {};
function render(name, data, escape) {
var contents;
module.exports = function (name, context, sync) {
var emitter = new events.EventEmitter;
// Check if already compiled
if (cache[name]) {
return cache[name](data);
}
var templateName = name + '.mustache';
var templatePath = path.join(__dirname, '../../templates/', templateName);
if (sync) {
if (!templates[templatePath]) templates[templatePath] = fs.readFileSync(templatePath, 'utf-8');
return hogan.compile(templates[templatePath]).renderWithColors(context);
} else if (templates[templatePath]) {
process.nextTick(function () {
emitter.emit('data', hogan.compile(templates[templatePath]).renderWithColors(context));
// Otherwise, read the file, compile and cache
contents = fs.readFileSync(path.join(templatesDir, name)).toString();
cache[name] = Handlebars.compile(contents, {
noEscape: !escape
});
} else {
fs.readFile(templatePath, 'utf-8', function (err, file) {
if (err) return emitter.emit('error', err);
templates[templatePath] = file;
emitter.emit('data', hogan.compile(file).renderWithColors(context));
});
}
// Call the function again
return render(name, data, escape);
}
return emitter;
};
function exists(name) {
if (cache[name]) {
return true;
}
return fs.existsSync(path.join(templatesDir, name));
}
module.exports = {
render: render,
exists: exists
};
{
"name": "bower",
"version": "1.0.0",
"description": "The browser package manager.",
"version": "0.10.0",
"author": "Twitter",

@@ -14,6 +14,6 @@ "licenses": [

"type": "git",
"url": "https://github.com/bower/bower"
"url": "git://github.com/bower/bower.git"
},
"main": "lib",
"homepage": "http://bower.io/",
"homepage": "http://bower.io",
"engines": {

@@ -23,32 +23,53 @@ "node": ">=0.8.0"

"dependencies": {
"archy": "0.0.2",
"abbrev": "~1.0.4",
"archy": "~0.0.2",
"async": "~0.2.5",
"bower-config": "~0.1.0",
"bower-endpoint-parser": "~0.1.0",
"bower-json": "~0.1.0",
"bower-logger": "~0.1.0",
"bower-registry-client": "~0.1.0",
"chmodr": "~0.1.0",
"colors": "~0.6.0-1",
"fstream": "~0.1.19",
"glob": "~3.1.14",
"hogan.js": "~2.0.0",
"lodash": "~1.0.1",
"mkdirp": "~0.3.4",
"nopt": "~2.0.0",
"promptly": "~0.1.0",
"rc": "~0.3.0",
"read-package-json": "~0.1.8",
"request": "~2.11.4",
"rimraf": "~2.0.3",
"semver": "~2.0.7",
"stable": "~0.1.2",
"tar": "~0.1.13",
"fstream": "~0.1.22",
"fstream-ignore": "~0.0.6",
"glob": "~3.2.1",
"graceful-fs": "~2.0.0",
"handlebars": "~1.0.11",
"inquirer": "~0.2.2",
"junk": "~0.2.0",
"mkdirp": "~0.3.5",
"mout": "~0.6.0",
"nopt": "~2.1.1",
"lru-cache": "~2.3.0",
"open": "0.0.3",
"promptly": "~0.2.0",
"q": "~0.9.2",
"request": "~2.22.0",
"request-progress": "~0.2.0",
"request-replay": "~0.1.2",
"rimraf": "~2.2.0",
"semver": "~2.0.8",
"stringify-object": "~0.1.4",
"tar": "~0.1.17",
"tmp": "~0.0.20",
"unzip": "0.1.7",
"unzip": "~0.1.7",
"update-notifier": "~0.1.3",
"which": "~1.0.5"
},
"devDependencies": {
"expect.js": "~0.2.0",
"grunt": "~0.4.1",
"grunt-simple-mocha": "~0.4.0",
"grunt-contrib-watch": "~0.5.0",
"grunt-contrib-jshint": "~0.6.0",
"grunt-execute": "~0.1.4",
"grunt-shell": "~0.3.0",
"mocha": "~1.12.0",
"nock": "~0.22.0",
"istanbul": "~0.1.42",
"proxyquire": "~0.4.1"
},
"scripts": {
"test": "mocha --reporter spec --timeout 40000"
"test": "grunt test"
},
"devDependencies": {
"mocha": "~1.8.1",
"nock": "~0.17.3"
},
"bin": {

@@ -55,0 +76,0 @@ "bower": "bin/bower"

@@ -25,3 +25,6 @@ # BOWER [![Build Status](https://secure.travis-ci.org/bower/bower.png?branch=master)](http://travis-ci.org/bower/bower)

Also make sure that [git](http://git-scm.com/) is installed as some bower
packages require it to be fetched and installed.
## Usage

@@ -41,4 +44,6 @@

bower install <package>
# Using a specific Git-tagged version from a remote package
# Using a specific version of a package
bower install <package>#<version>
# Using a different name and a specific version of a package
bower install <name>=<package>#<version>
```

@@ -51,3 +56,3 @@

public or private. ‡
* A local Git endpoint, i.e., a folder that's a Git repository. ‡
* A local endpoint, i.e., a folder that's a Git repository. ‡
* A shorthand endpoint, e.g., `someone/some-package` (defaults to GitHub). ‡

@@ -57,7 +62,7 @@ * A URL to a file, including `zip` and `tar` files. It's contents will be

‡ These types of `<package>` make Git tags available. You can specify a
[semver](http://semver.org/) tag to fetch a specific release, and lock the
package to that version.
‡ These types of `<package>` might have versions available. You can specify a
[semver](http://semver.org/) compatible version to fetch a specific release, and lock the
package to that version. You can also use ranges to specify a range of versions.
All package contents are installed in the `components` directory by default.
All package contents are installed in the `bower_components` directory by default.
You should **never** directly modify the contents of this directory.

@@ -131,57 +136,18 @@

Global configuration is handled by creating a `.bowerrc` in your home directory
(i.e., `~/.bowerrc`). Local configuration is handled by creating a `.bowerrc`
in your project's directory, allowing you to version a project-specific Bower
configuration with the rest of your code base.
The current spec can be read
[here](https://docs.google.com/document/d/1APq7oA9tNao1UYWyOm8dKqlRP2blVkROYLZ2fLIjtWc/edit#heading=h.4pzytc1f9j8k)
in the `Configuration` section.
Bower will combine the local and global configurations (with local settings
taking precedence).
The `.bowerrc` defines several options:
* `directory`: Set the default directory to install packaged components into.
* `endpoint`: Set a custom registry endpoint.
* `json`: Set the default JSON file for Bower to use when resolving dependencies.
* `searchpath`: An array of additional URLs pointing to read-only Bower registries.
* `shorthand_resolver`: Define a custom template for shorthand package names.
```json
{
"directory": "bower_components",
"endpoint": "https://bower.mycompany.com",
"json": "bower.json",
"searchpath": [
"https://bower.herokuapp.com"
],
"shorthand_resolver": "git://example.com/{{{ organization }}}/{{{ package }}}.git"
}
```
The `searchpath` array is useful if your organization wishes to maintain a
private registry of packages while also taking advantage of public Bower
registries. If a package is not found at your private endpoint, Bower will
consult the registries specified in the `searchpath` array.
The `shorthand_resolver` key provides support for defining a custom template
which Bower uses when constructing a URL for a given shorthand. For example, if
a shorthand of `twitter/flight` or `twitter/flight#v1.0.0` is specified in the
package manifest, the following data can be referenced from within the
`.bowerrc` as part of the `shorthand_resolver` template:
* `endpoint`: `twitter/flight`
* `organization`: `twitter`
* `package`: `flight`
**N.B.** To run your own Bower Endpoint for custom packages that are behind a
firewall, you can use a simple implementation of the [Bower Registry](https://github.com/bower/registry).
## Defining a package
You must create a JSON file -- `bower.json` by default -- in your project's
root, and specify all of its dependencies. This is similar to Node's
`package.json`, or Ruby's `Gemfile`, and is useful for locking down a project's
dependencies.
You must create a `bower.json` in your project's root, and specify all of its
dependencies. This is similar to Node's `package.json`, or Ruby's `Gemfile`,
and is useful for locking down a project's dependencies.
*NOTE:* In versions of Bower before 0.9.0 the package metadata file was called `component.json` rather than `bower.json`. This has changed to avoid a name clash with another tool. You can still use `component.json` for now but it is deprecated and the automatic fallback is likely to be removed in an upcoming release.
*NOTE:* In versions of Bower before 0.9.0 the package metadata file was called
`component.json` rather than `bower.json`. This has changed to avoid a name
clash with another tool. You can still use `component.json` for now but it is
deprecated and the automatic fallback is likely to be removed in an upcoming
release.

@@ -230,5 +196,4 @@ You can interactively create a `bower.json` with the following command:

If you pass the `--map` option to Bower's `list` command, it will generate JSON
with dependency objects. Alternatively, you can pass the `--paths` option to
the `list` command to get a simple path-to-name mapping:
If you pass the `--paths` option to Bower's `list` command, you will get a
simple path-to-name mapping:

@@ -243,3 +208,7 @@ ```json

Alternatively, every command supports the `--json` option that makes bower
output JSON. Command result is outputted to `stdout` and error/logs to
`stderr`.
## Programmatic API

@@ -268,18 +237,12 @@

Commands emit four types of events: `data`, `end`, `result`, and `error`.
Commands emit three types of events: `log`, `end`, and `error`.
`error` will only be emitted if something goes wrong. Not all commands emit all
events; for a detailed look, check out the code in `lib/commands`.
* `log` is emitted to report the state/progress of the command.
* `error` will only be emitted if something goes wrong.
* `end` is emitted when the command successfully ends.
`data` is typically a colorized string, ready to show to an end user. `search`
and `lookup` emit `packages` and `package`, respectively. Those events contain
a JSON representation of the result of the command.
For a better of idea how this works, you may want to check out [our bin
file](https://github.com/bower/bower/blob/master/bin/bower).
file](https://github.com/bower/bower/blob/rewrite/bin/bower).
For the install command, there is an additional `package` event that is emitted
for each installed/uninstalled package.
## Completion (experimental)

@@ -340,28 +303,31 @@

* [@addyosmani](https://github.com/addyosmani)
* [@angus-c](https://github.com/angus-c)
* [@borismus](https://github.com/borismus)
* [@carsonmcdonald](https://github/@carsonmcdonald)
* [@chriseppstein](https://github.com/chriseppstein)
* [@danwrong](https://github.com/danwrong)
* [@davidmaxwaterman](https://github.com/davidmaxwaterman)
* [@desandro](https://github.com/desandro)
* [@hemanth](https://github.com/hemanth)
* [@isaacs](https://github.com/isaacs)
* [@josh](https://github.com/josh)
* [@jrburke](https://github.com/jrburke)
* [@marcelombc](https://github.com/marcelombc)
* [@mklabs](https://github.com/mklabs)
* [@paulirish](https://github.com/paulirish)
* [@richo](https://github.com/richo)
* [@rvagg](https://github.com/rvagg)
* [@sindresorhus](https://github.com/sindresorhus)
* [@SlexAxton](https://github.com/SlexAxton)
* [@sstephenson](https://github.com/sstephenson)
* [@tomdale](https://github.com/tomdale)
* [@uzquiano](https://github.com/uzquiano)
* [@visionmedia](https://github.com/visionmedia)
* [@wagenet](https://github.com/wagenet)
* [@wibblymat](https://github.com/wibblymat)
* [@wycats](https://github.com/wycats)
[@addyosmani](https://github.com/addyosmani),
[@angus-c](https://github.com/angus-c),
[@borismus](https://github.com/borismus),
[@carsonmcdonald](https://github.com/carsonmcdonald),
[@chriseppstein](https://github.com/chriseppstein),
[@danwrong](https://github.com/danwrong),
[@davidmaxwaterman](https://github.com/davidmaxwaterman),
[@desandro](https://github.com/desandro),
[@hemanth](https://github.com/hemanth),
[@isaacs](https://github.com/isaacs),
[@josh](https://github.com/josh),
[@jrburke](https://github.com/jrburke),
[@marcelombc](https://github.com/marcelombc),
[@marcooliveira](https://github.com/marcooliveira),
[@mklabs](https://github.com/mklabs),
[@necolas](https://github.com/necolas),
[@paulirish](https://github.com/paulirish),
[@richo](https://github.com/richo),
[@rvagg](https://github.com/rvagg),
[@sindresorhus](https://github.com/sindresorhus),
[@SlexAxton](https://github.com/SlexAxton),
[@sstephenson](https://github.com/sstephenson),
[@svnlto](https://github.com/svnlto),
[@tomdale](https://github.com/tomdale),
[@uzquiano](https://github.com/uzquiano),
[@visionmedia](https://github.com/visionmedia),
[@wagenet](https://github.com/wagenet),
[@wibblymat](https://github.com/wibblymat),
[@wycats](https://github.com/wycats)

@@ -368,0 +334,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc