extra-npm
Version:
Common utility commands for npm packages.
135 lines (113 loc) • 4.51 kB
JavaScript
// Searches for packages.
const kleur = require('kleur');
const boolean = require('extra-boolean').parse;
const _package = require('./_package.js');
const E = process.env;
const OPTIONS = {
query: null,
silent: boolean(E['NPM_SILENT']||'0'),
long: boolean(E['NPM_SEARCH_LONG']||'0'),
json: boolean(E['NPM_SEARCH_JSON']||'0'),
parseable: boolean(E['NPM_SEARCH_PARSEABLE']||'0'),
description: boolean(E['NPM_SEARCH_DESCRIPTION']||'1'),
searchopts: E['NPM_SEARCH_SEARCHOPTS']||'',
searchexclude: E['NPM_SEARCH_SEARCHEXCLUDE']||'',
searchstaleness: parseInt(E['NPM_SEARCH_SEARCHSTALELESS']||'900', 10),
limit: parseInt(E['NPM_SEARCH_LIMIT']||'20', 10),
offset: parseInt(E['NPM_SEARCH_OFFSET']||'0', 10),
detailed: boolean(E['NPM_SEARCH_DETAILED']||'1'),
sortBy: E['NPM_SEARCH_SORTBY']||'optimal',
ascending: boolean(E['NPM_SEARCH_ASCENDING']||'0'),
fields: E['NPM_SEARCH_FIELDS']||'name,version,description,author'
};
// Get ellipsis text.
function ellipsis(txt, len) {
return txt.length>len? txt.substring(0, len-3)+'...' : txt.padEnd(len, ' ');
}
// Get map from arrays.
function mapFrom(a, b) {
var map = new Map();
for (var i=0, I=a.length; i<I; i++)
map.set(a[i], b[i]);
return map;
}
// Get output sizes.
function outputSizes(as, flds) {
var cols = (process.stdout.columns||Number.MAX_SAFE_INTEGER)-3*flds.length-1;
var sizs = flds.map(f => Math.max.apply(null, as.map(a => Math.min(_package.fstring(a, f).length, 32)).concat([f.length])));
var sizt = sizs.reduce((a, v) => a+v);
return sizt>cols? sizs.map(v => Math.floor(v*(cols/sizt))) : sizs;
}
// Get highlighted text.
function highlight(out, qry, fn) {
for (var re of qry.replace(/\W+/g, ' ').split(' ').map(v => new RegExp(v, 'gi')))
out = out.replace(re, m => fn(m));
return out;
}
// Output in default mode.
function outputDefault(as, flds, qry) {
var sizm = mapFrom(flds, outputSizes(as, flds));
var top = '| '+flds.map(f => ellipsis(f, sizm.get(f))).join(' | ')+' |';
console.log(top); console.log('-'.repeat(top.length));
for (var a of as) {
var lin = '| '+flds.map(f => ellipsis(_package.fstring(a, f), sizm.get(f))).join(' | ')+' |';
console.log(highlight(lin, qry, kleur.red));
}
}
// Output in parseable mode.
function outputParseable(as, flds) {
for (var a of as)
console.log(flds.map(f => _package.fstring(a, f)).join('\t'));
}
// Output in JSON mode.
function outputJson(as) {
console.log('[');
for (var i=0, I=as.length; i<I; i++)
console.log(JSON.stringify(as[i])+(i!=I-1? ',':''));
console.log(']');
}
// pre: sortBy
// progress 10%, 80%, 10%
async function search(qry, o) {
var o = Object.assign({}, OPTIONS, o);
var qry = _package.query(qry, o.searchopts||[], o.searchexclude||[]), rnk = _package.ranking(o.sortBy);
var as = await _package.search(qry, rnk, rnk? o.offset:0, rnk? o.limit:Number.MAX_SAFE_INTEGER);
var flds = o.fields.split(','); if (!rnk) flds.push(o.sortBy);
await _package.populate(as, flds);
if (!rnk) _package.sortBy(as, o.sortBy);
if (o.ascending) as = as.reverse();
if (!rnk) as = as.slice(o.offset, o.limit);
if (o.json) outputJson(as);
else if (o.parseable) outputParseable(as, flds);
else outputDefault(as, flds, qry);
}
module.exports = search;
// Get options from arguments.
function options(o, k, a, i) {
o.query = o.query||'';
if (k==='--silent') o.silent = true;
else if (k==='-l' || k==='--long') o.long = true;
else if (k==='--json') o.json = true;
else if (k==='--parseable') o.parseable = true;
else if (k==='--no-description') o.description = false;
else if (k==='--searchopts') o.searchopts = a[++i];
else if (k==='--searchexclude') o.searchexclude = a[++i];
else if (k==='--searchstaleness') o.searchstaleness = parseInt(a[++i], 10);
else if (k==='--limit') o.limit = parseInt(a[++i], 10);
else if (k==='--offset') o.offset = parseInt(a[++i], 10);
else if (k==='--detailed') o.detailed = true;
else if (k==='--sortby') o.sortBy = a[++i];
else if (k==='--ascending') o.ascending = true;
else if (k==='--fields') o.fields = a[++i];
else o.query += a[i]+' ';
return i+1;
}
// Run on shell.
function shell(a) {
var o = {query: ''};
for (var i=2, I=a.length; i<I;)
i = options(o, a[i], a, i);
search(o.query.trim(), o);
}
if (require.main===module) shell(process.argv);