11cb0ef41Sopenharmony_ciconst { Minipass } = require('minipass') 21cb0ef41Sopenharmony_ciconst Pipeline = require('minipass-pipeline') 31cb0ef41Sopenharmony_ciconst libSearch = require('libnpmsearch') 41cb0ef41Sopenharmony_ciconst log = require('../utils/log-shim.js') 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ciconst formatSearchStream = require('../utils/format-search-stream.js') 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_cifunction filter (data, include, exclude) { 91cb0ef41Sopenharmony_ci const words = [data.name] 101cb0ef41Sopenharmony_ci .concat(data.maintainers.map(m => `=${m.username}`)) 111cb0ef41Sopenharmony_ci .concat(data.keywords || []) 121cb0ef41Sopenharmony_ci .map(f => f && f.trim && f.trim()) 131cb0ef41Sopenharmony_ci .filter(f => f) 141cb0ef41Sopenharmony_ci .join(' ') 151cb0ef41Sopenharmony_ci .toLowerCase() 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci if (exclude.find(e => match(words, e))) { 181cb0ef41Sopenharmony_ci return false 191cb0ef41Sopenharmony_ci } 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci return true 221cb0ef41Sopenharmony_ci} 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_cifunction match (words, pattern) { 251cb0ef41Sopenharmony_ci if (pattern.startsWith('/')) { 261cb0ef41Sopenharmony_ci if (pattern.endsWith('/')) { 271cb0ef41Sopenharmony_ci pattern = pattern.slice(0, -1) 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci pattern = new RegExp(pattern.slice(1)) 301cb0ef41Sopenharmony_ci return words.match(pattern) 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci return words.indexOf(pattern) !== -1 331cb0ef41Sopenharmony_ci} 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciconst BaseCommand = require('../base-command.js') 361cb0ef41Sopenharmony_ciclass Search extends BaseCommand { 371cb0ef41Sopenharmony_ci static description = 'Search for packages' 381cb0ef41Sopenharmony_ci static name = 'search' 391cb0ef41Sopenharmony_ci static params = [ 401cb0ef41Sopenharmony_ci 'long', 411cb0ef41Sopenharmony_ci 'json', 421cb0ef41Sopenharmony_ci 'color', 431cb0ef41Sopenharmony_ci 'parseable', 441cb0ef41Sopenharmony_ci 'description', 451cb0ef41Sopenharmony_ci 'searchopts', 461cb0ef41Sopenharmony_ci 'searchexclude', 471cb0ef41Sopenharmony_ci 'registry', 481cb0ef41Sopenharmony_ci 'prefer-online', 491cb0ef41Sopenharmony_ci 'prefer-offline', 501cb0ef41Sopenharmony_ci 'offline', 511cb0ef41Sopenharmony_ci ] 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci static usage = ['[search terms ...]'] 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci async exec (args) { 561cb0ef41Sopenharmony_ci const opts = { 571cb0ef41Sopenharmony_ci ...this.npm.flatOptions, 581cb0ef41Sopenharmony_ci ...this.npm.flatOptions.search, 591cb0ef41Sopenharmony_ci include: args.map(s => s.toLowerCase()).filter(s => s), 601cb0ef41Sopenharmony_ci exclude: this.npm.flatOptions.search.exclude.split(/\s+/), 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci if (opts.include.length === 0) { 641cb0ef41Sopenharmony_ci throw new Error('search must be called with arguments') 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci // Used later to figure out whether we had any packages go out 681cb0ef41Sopenharmony_ci let anyOutput = false 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci class FilterStream extends Minipass { 711cb0ef41Sopenharmony_ci constructor () { 721cb0ef41Sopenharmony_ci super({ objectMode: true }) 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci write (pkg) { 761cb0ef41Sopenharmony_ci if (filter(pkg, opts.include, opts.exclude)) { 771cb0ef41Sopenharmony_ci super.write(pkg) 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci const filterStream = new FilterStream() 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci // Grab a configured output stream that will spit out packages in the desired format. 851cb0ef41Sopenharmony_ci const outputStream = await formatSearchStream({ 861cb0ef41Sopenharmony_ci args, // --searchinclude options are not highlighted 871cb0ef41Sopenharmony_ci ...opts, 881cb0ef41Sopenharmony_ci }) 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci log.silly('search', 'searching packages') 911cb0ef41Sopenharmony_ci const p = new Pipeline( 921cb0ef41Sopenharmony_ci libSearch.stream(opts.include, opts), 931cb0ef41Sopenharmony_ci filterStream, 941cb0ef41Sopenharmony_ci outputStream 951cb0ef41Sopenharmony_ci ) 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci p.on('data', chunk => { 981cb0ef41Sopenharmony_ci if (!anyOutput) { 991cb0ef41Sopenharmony_ci anyOutput = true 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci this.npm.output(chunk.toString('utf8')) 1021cb0ef41Sopenharmony_ci }) 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci await p.promise() 1051cb0ef41Sopenharmony_ci if (!anyOutput && !this.npm.config.get('json') && !this.npm.config.get('parseable')) { 1061cb0ef41Sopenharmony_ci this.npm.output('No matches found for ' + (args.map(JSON.stringify).join(' '))) 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci log.silly('search', 'search completed') 1101cb0ef41Sopenharmony_ci log.clearProgress() 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci} 1131cb0ef41Sopenharmony_cimodule.exports = Search 114