UNPKG

github-star

Version:

Star, unstar, or check if you starred a repository or the repositories associated with NPM, Bower, or Meteor package file dependencies on GitHub

318 lines (282 loc) 13.8 kB
(function(root, factory) { if (typeof define === 'function' && define.amd) { define(['lodash', 'superagent'], factory); } else if (typeof exports === 'object') { module.exports = factory( require('lodash'), require('superagent'), require('fs'), require('url'), require('path'), require('async'), require('github-url-to-object'), require('bower-package-url'), require('atmosphere-package-info'), require('package-json'), require('pascal-case') ); } else { root.githubStar = factory(root._, root.superagent); } }(this, function(_, http, fs, url, path, async, ghUrlToObject, bowerPackageURL, atmospherePackageInfo, packageJSONInfo, pascalCase) { return function(username, tokenOrPassword) { if (!_.isString(username)) { if (fs && _.isString(process.env.GITHUB_USERNAME)) { username = process.env.GITHUB_USERNAME; } else { throw new TypeError('username argument or GITHUB_USERNAME environment variable must be a string'); } } if (!_.isString(tokenOrPassword)) { if (fs && _.isString(process.env.GITHUB_TOKEN)) { tokenOrPassword = process.env.GITHUB_TOKEN; } else { throw new TypeError('tokenOrPassword argument or GITHUB_TOKEN environment variable must be a string'); } } var validateMethod = function(method) { return _.includes(['star', 'unstar', 'isStarred'], method) ? null : new TypeError('method must be "star", "unstar", or "isStarred"'); }, repository = function(method, author, repo, cb) { var methodErr = validateMethod(method); if (!_.isFunction(cb)) { throw new TypeError('cb must be a function'); } if (!_.isString(author)) { cb(new TypeError('author must be a string')); return; } if (!_.isString(repo)) { cb(new TypeError('repo must be a string')); return; } if (methodErr) { cb(methodErr); return; } var authorRepo = author + '/' + repo; http[method === 'star' ? 'put' : method === 'unstar' ? 'del' : 'get'] ('https://api.github.com/user/starred/' + authorRepo) .set('Content-Length', 0) .auth(username, tokenOrPassword) .end(function(err, res) { var isChecking = method === 'isStarred'; if (_.isObject(err)) { var is404 = res.statusCode === 404, prefix = 'Repo "' + authorRepo; err = isChecking && is404 ? null : new Error( is404 ? prefix + '" not found on GitHub' : prefix + ': ' + err.status + ' ' + err.message ); } cb(err, isChecking ? res.statusCode === 204 : undefined); }); }, dependencies = { readAndParse: function(opt, cb) { fs.readFile(opt.depsPath, function(err, data) { if (err) { cb(err); return; } try { opt.deps = _.chain(JSON.parse(data)) .filter(function(val, key) { return (opt.dependencies && key === 'dependencies') || (opt.devDependencies && key === 'devDependencies'); }) .reduce(function(result, val) { return _.merge(result, val); }, {}) .value(); opt.type = opt.type || (_.isString(opt.depsPath) && path.parse(opt.depsPath).base === 'bower.json') ? 'Bower' : 'NPM'; } catch (e) { opt.deps = _.reduce(data.toString().split('\n'), function(result, line) { if (line.length > 1 && line[0] !== '#') { result.push(line.trim()); } return result; }, []); opt.type = 'Atmosphere'; if (!opt.deps.length) { err = new SyntaxError('Unable to parse NPM / Bower / Atmosphere dependencies'); } } cb(err); }); }, callRepositoryMethod: function(opt, pkgErr, name, url, done) { var ghObject = ghUrlToObject(url); if (pkgErr || !ghObject) { opt.results[name] = pkgErr ? pkgErr : !ghObject ? new Error(url + ' is not a GitHub repository') : null; done(); return; } var author = ghObject.user, repo = ghObject.repo; if ((opt.skipSelf && username === author) || _.includes(opt.skippedAuthors, author) || _.includes(opt.skippedRepos, repo)) { done(); return; } api.repository[opt.method](author, repo, function(err, isStarred) { opt.results[name] = err ? err : opt.method === 'isStarred' ? isStarred : !err; done(); }); }, process: { init: function(method, opt, cb) { var methodErr = validateMethod(method); if (!_.isFunction(cb)) { throw new TypeError('cb must be a function'); } if (methodErr) { cb(methodErr, {}); return; } if (!fs) { cb(new Error('dependencies methods are only supported in CommonJS environments'), {}); return; } if (!_.isObject(opt)) { cb(new TypeError('opt must be an object'), {}); return; } if (_.isArray(opt.depsList)) { if (!_.isString(opt.type)) { _.each(opt.depsList, function(dep) { if (_.isString(dep) && _.includes(dep, ':')) { opt.type = 'Atmosphere'; return false; } }); if (!_.isString(opt.type)) { cb(new Error('Unable to determine the package manager associated with ' + 'opt.depsList. Please specify "NPM" or "Bower" (case-insensitive) for ' + 'opt.type'), {}); return; } } } else { if (!_.isString(opt.depsPath)) { cb(new TypeError('opt.depsPath must be a string path to a Atmosphere, NPM, or Bower ' + 'package file, or opt.depsList must be an array of package names'), {}); return; } if (!_.isBoolean(opt.dependencies)) { opt.dependencies = true; } if (!_.isBoolean(opt.devDependencies)) { opt.devDependencies = true; } if (!opt.dependencies && !opt.devDependencies) { cb(new Error('opt.dependencies and opt.devDependencies cannot both be false'), {}); return; } } if (_.isString(opt.type)) { var upperType = opt.type.toUpperCase(); opt.type = upperType === 'NPM' ? upperType : pascalCase(opt.type); } opt.results = {}; opt.method = method; if (opt.depsPath) { dependencies.readAndParse(opt, function(err) { if (err) { cb(err, {}); return; } dependencies.process.callPackageManagerMethod(opt, cb); }); } else { opt.deps = opt.depsList; dependencies.process.callPackageManagerMethod(opt, cb); } }, callPackageManagerMethod: function(opt, cb) { opt.type === 'Atmosphere' ? dependencies.process.atmosphere(opt, cb) : dependencies.process.npmOrBower(opt, cb); }, npmOrBower: function(opt, cb) { var repoMethod = _.partial(dependencies.callRepositoryMethod, opt); async.forEachOf( opt.deps, function(versionOrURLOrName, name, done) { if (opt.depsList) { name = versionOrURLOrName; } if (ghUrlToObject(versionOrURLOrName)) { repoMethod(null, name, versionOrURLOrName, done); } else if (opt.type === 'Bower') { bowerPackageURL(name, function(err, url) { repoMethod(err, name, url, done); }); } else { packageJSONInfo(name, 'latest').then(function(info) { repoMethod(null, name, info.repository.url, done); }).catch(function(err) { repoMethod(err, name, null, done); }); } }, function() { cb(null, opt.results); } ); }, atmosphere: function(opt, cb) { atmospherePackageInfo(opt.deps, function(err, packages) { if (err) { cb(err, {}); return; } async.forEachOf(packages, function(data, name, done) { var err = data instanceof Error ? data : null, repo = _.get(data, 'latestVersion.git'); dependencies.callRepositoryMethod(opt, err, name, repo, done); }, function() { cb(null, opt.results); }); }); } } }, api = { repository: { star: function(author, repo, cb) { repository('star', author, repo, cb); }, unstar: function(author, repo, cb) { repository('unstar', author, repo, cb); }, isStarred: function(author, repo, cb) { repository('isStarred', author, repo, cb); } }, dependencies: { star: function(opt, cb) { dependencies.process.init('star', opt, cb); }, unstar: function(opt, cb) { dependencies.process.init('unstar', opt, cb); }, areStarred: function(opt, cb) { dependencies.process.init('isStarred', opt, cb); } } }; return api; }; }));