brackets-npm-registry
Version:
Install your extensions into Brackets using npm
288 lines (254 loc) • 9.59 kB
JavaScript
/*eslint strict:0, no-console:0*/
;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
var _ = require('lodash');
var cheerio = require('cheerio');
var npmKeyword = require('npm-keyword');
var Promise = require('bluebird');
var _require = require('bluebird');
var all = _require.all;
var promisifyAll = _require.promisifyAll;
var fs = promisifyAll(require('fs-extra'));
var path = require('path');
var request = require('request');
var semver = require('semver');
var logOutput = function logOutput() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return process.stdout.write(args.join(' '), 'utf8');
};
var logProgress = function logProgress() {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return process.stderr.write(args.join(' '), 'utf8');
};
function calculateDownloadMetrics(extensionInfo) {
var downloadsArray = extensionInfo.downloads;
// downloadsLastWeek
var today = new Date();
today.setDate(today.getDate() - 7);
var weekAgo = today.toISOString().substring(0, 10);
extensionInfo.downloadsLastWeek = downloadsArray.filter(function (obj) {
return obj.day >= weekAgo;
}).reduce(function (sum, obj) {
return sum + obj.downloads;
}, 0);
// downloadsTotal
extensionInfo.downloadsTotal = downloadsArray.reduce(function (sum, obj) {
return sum + obj.downloads;
}, 0);
}
function getPackagesFromNpmSearch() {
// eslint-disable-line no-unused-vars
return new Promise(function (resolve, reject) {
request('http://npmsearch.com/query?q=keywords:brackets-extension&fields=name', function (error, response, body) {
if (error) {
return reject(error);
}
if (!/^2/.test(response.statusCode)) {
return reject(body);
}
if (typeof body === 'string') {
try {
body = JSON.parse(body);
} catch (err) {
return reject(err);
}
}
var results = [];
body.results.forEach(function (x) {
if (_.isArray(x.name)) {
x.name.forEach(function (n) {
return results.push(n);
});
} else {
results.push(x.name);
}
});
resolve(results.sort()); // array of strings
});
});
}
// https://registry.npmjs.org/-/_view/byKeyword?startkey=[%22brackets-extension%22]&endkey=[%22brackets-extension%22,%7B%7D]&group_level=2
function getPackagesFromNpmKeyword() {
return npmKeyword.names('brackets-extension');
}
function npmView(packageName) {
return new Promise(function (resolve, reject) {
request('https://registry.npmjs.org/' + packageName, function (error, response, body) {
if (error) {
return reject(error);
}
if (!/^2/.test(response.statusCode)) {
return reject(body);
}
if (typeof body === 'string') {
try {
body = JSON.parse(body);
} catch (err) {
return reject(err);
}
}
// cleanup a bit
delete body.readme;
resolve(body);
});
});
}
function getDownloadCounts(extensionInfos) {
var from = '2015-01-01';
var to = new Date().toISOString().substring(0, 10);
var extensionIds = extensionInfos.map(function (i) {
return i.name;
});
return new Promise(function (resolve, reject) {
request('https://api.npmjs.org/downloads/range/' + from + ':' + to + '/' + extensionIds.join(','), function (error, response, body) {
if (error) {
return reject(error);
}
if (!/^2/.test(response.statusCode)) {
return reject(body);
}
if (typeof body === 'string') {
try {
body = JSON.parse(body);
} catch (err) {
return reject(err);
}
}
if (extensionIds.length === 1) {
extensionInfos[0].downloads = body.downloads;
calculateDownloadMetrics(extensionInfos[0]);
} else {
extensionInfos.forEach(function (extensionInfo) {
var info = body[extensionInfo.name];
if (info && info.downloads) {
extensionInfo.downloads = info.downloads;
calculateDownloadMetrics(extensionInfo);
}
});
}
resolve(extensionInfos);
});
});
}
function buildRegistry(targetFile) {
logProgress('getting packages with keyword: brackets-extension');
getPackagesFromNpmKeyword().then(function (searchResults) {
// call view for all potential extensions
logProgress('executing npm view to get detailed info about the extensions (' + searchResults.length + ')');
return all(searchResults.map(function (extensionId) {
return npmView(extensionId);
}));
}).then(function (viewResults) {
logProgress('got all view results (' + viewResults.length + ')');
// filter out those, which doesn't have brackets engine specified in any of the versions
return viewResults.filter(function (result) {
// versions sorted from latest first
var versions = Object.keys(result.versions).sort(function (a, b) {
return -1 * semver.compare(a, b);
});
// engine versions found in the versions
var engines = {};
// filter out only relevant versions (we don't want duplicates with the same brackets version)
versions = versions.filter(function (version) {
var bracketsEngine = _.get(result.versions[version], 'engines.brackets');
if (!bracketsEngine || engines[bracketsEngine]) {
delete result.versions[version];
return false;
}
engines[bracketsEngine] = true;
return true;
});
if (versions.length === 0) {
logProgress('filtering out ' + result.name + ' because no valid versions with brackets-engine were found\n');
return false;
}
// add data from the latest version to the root
_.defaults(result, result.versions[versions[0]]);
return true;
});
}).then(function (extensionInfos) {
logProgress('getting download info counts for the extensions (' + extensionInfos.length + ')');
// get download counts for the extensions
return getDownloadCounts(extensionInfos)['catch'](function (err) {
logProgress('getDownloadCounts-error: ' + err);
return extensionInfos;
});
}).then(function (extensionInfos) {
logProgress('getting issue/pr counts for the extensions');
return Promise.all(extensionInfos.map(function (extensionInfo) {
var githubRepo = /https?:\/\/[^\/]*github.com\/([^\/]+)\/([^\/]+)$/;
var candidates = _.compact([extensionInfo.repository ? extensionInfo.repository.url : null, extensionInfo.repository, extensionInfo.homepage]).filter(function (x) {
return typeof x === 'string';
}).filter(function (x) {
return x.match(githubRepo);
});
if (candidates.length === 0) {
return Promise.resolve();
}
var m = candidates[0].match(githubRepo);
var username = m[1];
var repo = m[2];
if (repo.match(/\.git$/)) {
repo = repo.slice(0, -4);
}
extensionInfo.github = {};
extensionInfo.github.username = username;
extensionInfo.github.repository = repo;
extensionInfo.github.issueCount = -1;
extensionInfo.github.pullCount = -1;
var githubIssueCount = NaN;
var githubPullCount = NaN;
return new Promise(function (resolve) {
var url = 'https://github.com/' + username + '/' + repo + '/issues';
request({
url: url,
method: 'GET',
headers: {
'User-Agent': 'brackets-npm-registry'
}
}, function (error, response, body) {
if (error || response.statusCode !== 200) {
if (response) {
logProgress('GET ' + url + ' ERR', response.statusCode);
} else {
logProgress('GET ' + url + ' ERR', error);
}
return resolve();
}
var parsedBody = cheerio.load(body);
githubIssueCount = parseInt(parsedBody('a[href="/' + username + '/' + repo + '/issues"] .counter').text(), 10);
githubPullCount = parseInt(parsedBody('a[href="/' + username + '/' + repo + '/pulls"] .counter').text(), 10);
resolve();
});
}).then(function () {
extensionInfo.github.issueCount = isNaN(githubIssueCount) ? -1 : githubIssueCount;
extensionInfo.github.pullCount = isNaN(githubPullCount) ? -1 : githubPullCount;
});
})).then(function () {
return extensionInfos;
});
}).then(function (extensionInfos) {
var strResults = JSON.stringify(extensionInfos, null, 2);
logProgress('all done');
logOutput(strResults);
if (targetFile) {
logProgress('writing the results to file:\n', targetFile);
return fs.ensureDirAsync(path.dirname(targetFile)).then(function () {
return fs.writeFileAsync(targetFile, strResults);
}).then(function () {
return extensionInfos;
});
}
return extensionInfos;
});
}
if (process.argv[1] === __filename) {
buildRegistry.apply(undefined, _toConsumableArray(process.argv.slice(2)));
} else {
module.exports = buildRegistry;
}
//# sourceMappingURL=C:\Users\Zaggi\AppData\Roaming\Brackets-Electron\extensions\user\brackets-npm-registry\dist//node/registry-builder.js.map