summaryrefslogtreecommitdiff
path: root/deps/npm/lib/search.js
diff options
context:
space:
mode:
authorKat Marchán <kzm@sykosomatic.org>2016-12-18 20:22:09 -0800
committerMyles Borins <myles.borins@gmail.com>2016-12-28 15:30:50 -0500
commit9946519fba73687d34dccd5813808252a1973f3c (patch)
tree74d7194d2a00743bcd905027195e7e8000c5ac5a /deps/npm/lib/search.js
parent4d3b487b791606ea965f6280ce0eeea03d79b660 (diff)
downloadandroid-node-v8-9946519fba73687d34dccd5813808252a1973f3c.tar.gz
android-node-v8-9946519fba73687d34dccd5813808252a1973f3c.tar.bz2
android-node-v8-9946519fba73687d34dccd5813808252a1973f3c.zip
deps: upgrade npm to 4.0.5
PR-URL: https://github.com/nodejs/node/pull/10330 Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/npm/lib/search.js')
-rw-r--r--deps/npm/lib/search.js321
1 files changed, 69 insertions, 252 deletions
diff --git a/deps/npm/lib/search.js b/deps/npm/lib/search.js
index cd6d5ed8ea..c9f3628717 100644
--- a/deps/npm/lib/search.js
+++ b/deps/npm/lib/search.js
@@ -1,11 +1,15 @@
+'use strict'
module.exports = exports = search
var npm = require('./npm.js')
-var columnify = require('columnify')
-var updateIndex = require('./cache/update-index.js')
+var allPackageMetadata = require('./search/all-package-metadata.js')
+var packageFilter = require('./search/package-filter.js')
+var formatPackageStream = require('./search/format-package-stream.js')
var usage = require('./utils/usage')
var output = require('./utils/output.js')
+var log = require('npmlog')
+var ms = require('mississippi')
search.usage = usage(
'search',
@@ -13,276 +17,89 @@ search.usage = usage(
)
search.completion = function (opts, cb) {
- var compl = {}
- var partial = opts.partialWord
- var ipartial = partial.toLowerCase()
- var plen = partial.length
-
- // get the batch of data that matches so far.
- // this is an example of using npm.commands.search programmatically
- // to fetch data that has been filtered by a set of arguments.
- search(opts.conf.argv.remain.slice(2), true, function (er, data) {
- if (er) return cb(er)
- Object.keys(data).forEach(function (name) {
- data[name].words.split(' ').forEach(function (w) {
- if (w.toLowerCase().indexOf(ipartial) === 0) {
- compl[partial + w.substr(plen)] = true
- }
- })
- })
- cb(null, Object.keys(compl))
- })
+ cb(null, [])
}
-function search (args, silent, staleness, cb) {
- if (typeof cb !== 'function') {
- cb = staleness
- staleness = 600
- }
- if (typeof cb !== 'function') {
- cb = silent
- silent = false
- }
-
- var searchopts = npm.config.get('searchopts')
- var searchexclude = npm.config.get('searchexclude')
+function search (args, cb) {
+ var staleness = npm.config.get('searchstaleness')
- if (typeof searchopts !== 'string') searchopts = ''
- searchopts = searchopts.split(/\s+/)
- var opts = searchopts.concat(args).map(function (s) {
- return s.toLowerCase()
- }).filter(function (s) { return s })
-
- if (opts.length === 0) {
+ var include = prepareIncludes(args, npm.config.get('searchopts'))
+ if (include.length === 0) {
return cb(new Error('search must be called with arguments'))
}
- if (typeof searchexclude === 'string') {
- searchexclude = searchexclude.split(/\s+/)
- } else {
- searchexclude = []
- }
- searchexclude = searchexclude.map(function (s) {
- return s.toLowerCase()
- })
-
- getFilteredData(staleness, opts, searchexclude, function (er, data) {
- // now data is the list of data that we want to show.
- // prettify and print it, and then provide the raw
- // data to the cb.
- if (er || silent) return cb(er, data)
- output(prettify(data, args))
- cb(null, data)
- })
-}
-
-function getFilteredData (staleness, args, notArgs, cb) {
- updateIndex(staleness, function (er, data) {
- if (er) return cb(er)
- return cb(null, filter(data, args, notArgs))
- })
-}
-
-function filter (data, args, notArgs) {
- // data={<name>:{package data}}
- return Object.keys(data).map(function (d) {
- return data[d]
- }).filter(function (d) {
- return typeof d === 'object'
- }).map(stripData).map(getWords).filter(function (data) {
- return filterWords(data, args, notArgs)
- }).reduce(function (l, r) {
- l[r.name] = r
- return l
- }, {})
-}
-
-function stripData (data) {
- return {
- name: data.name,
- description: npm.config.get('description') ? data.description : '',
- maintainers: (data.maintainers || []).map(function (m) {
- return '=' + m.name
- }),
- url: !Object.keys(data.versions || {}).length ? data.url : null,
- keywords: data.keywords || [],
- version: Object.keys(data.versions || {})[0] || [],
- time: data.time &&
- data.time.modified &&
- (new Date(data.time.modified).toISOString() // remove time
- .split('T').join(' ')
- .replace(/:[0-9]{2}\.[0-9]{3}Z$/, ''))
- .slice(0, -5) ||
- 'prehistoric'
- }
-}
-
-function getWords (data) {
- data.words = [ data.name ]
- .concat(data.description)
- .concat(data.maintainers)
- .concat(data.url && ('<' + data.url + '>'))
- .concat(data.keywords)
- .map(function (f) { return f && f.trim && f.trim() })
- .filter(function (f) { return f })
- .join(' ')
- .toLowerCase()
- return data
-}
-
-function filterWords (data, args, notArgs) {
- var words = data.words
- for (var i = 0, l = args.length; i < l; i++) {
- if (!match(words, args[i])) return false
- }
- for (i = 0, l = notArgs.length; i < l; i++) {
- if (match(words, notArgs[i])) return false
- }
- return true
-}
-
-function match (words, arg) {
- if (arg.charAt(0) === '/') {
- arg = arg.replace(/\/$/, '')
- arg = new RegExp(arg.substr(1, arg.length - 1))
- return words.match(arg)
- }
- return words.indexOf(arg) !== -1
-}
+ var exclude = prepareExcludes(npm.config.get('searchexclude'))
-function prettify (data, args) {
- var searchsort = (npm.config.get('searchsort') || 'NAME').toLowerCase()
- var sortField = searchsort.replace(/^\-+/, '')
- var searchRev = searchsort.charAt(0) === '-'
- var truncate = !npm.config.get('long')
+ // Used later to figure out whether we had any packages go out
+ var anyOutput = false
- if (Object.keys(data).length === 0) {
- return 'No match found for ' + (args.map(JSON.stringify).join(' '))
- }
+ // Get a stream with *all* the packages. This takes care of dealing
+ // with the local cache as well, but that's an internal detail.
+ var allEntriesStream = allPackageMetadata(staleness)
- var lines = Object.keys(data).map(function (d) {
- // strip keyname
- return data[d]
- }).map(function (dat) {
- dat.author = dat.maintainers
- delete dat.maintainers
- dat.date = dat.time
- delete dat.time
- return dat
- }).map(function (dat) {
- // split keywords on whitespace or ,
- if (typeof dat.keywords === 'string') {
- dat.keywords = dat.keywords.split(/[,\s]+/)
- }
- if (Array.isArray(dat.keywords)) {
- dat.keywords = dat.keywords.join(' ')
- }
-
- // split author on whitespace or ,
- if (typeof dat.author === 'string') {
- dat.author = dat.author.split(/[,\s]+/)
- }
- if (Array.isArray(dat.author)) {
- dat.author = dat.author.join(' ')
- }
- return dat
+ // Grab a stream that filters those packages according to given params.
+ var searchSection = (npm.config.get('unicode') ? '🤔 ' : '') + 'search'
+ var filterStream = streamFilter(function (pkg) {
+ log.gauge.pulse('search')
+ log.gauge.show({section: searchSection, logline: 'scanning ' + pkg.name})
+ // Simply 'true' if the package matches search parameters.
+ var match = packageFilter(pkg, include, exclude, {
+ description: npm.config.get('description')
+ })
+ if (match) { anyOutput = true }
+ return match
})
- lines.sort(function (a, b) {
- var aa = a[sortField].toLowerCase()
- var bb = b[sortField].toLowerCase()
- return aa === bb ? 0
- : aa < bb ? -1 : 1
+ // Grab a configured output stream that will spit out packages in the
+ // desired format.
+ var outputStream = formatPackageStream({
+ args: args, // --searchinclude options are not highlighted
+ long: npm.config.get('long'),
+ description: npm.config.get('description'),
+ json: npm.config.get('json'),
+ parseable: npm.config.get('parseable'),
+ color: npm.color
+ })
+ outputStream.on('data', function (chunk) {
+ output(chunk.toString('utf8'))
})
- if (searchRev) lines.reverse()
-
- var columns = npm.config.get('description')
- ? ['name', 'description', 'author', 'date', 'version', 'keywords']
- : ['name', 'author', 'date', 'version', 'keywords']
-
- var output = columnify(
- lines,
- {
- include: columns,
- truncate: truncate,
- config: {
- name: { maxWidth: 40, truncate: false, truncateMarker: '' },
- description: { maxWidth: 60 },
- author: { maxWidth: 20 },
- date: { maxWidth: 11 },
- version: { maxWidth: 11 },
- keywords: { maxWidth: Infinity }
- }
+ log.silly('search', 'searching packages')
+ ms.pipe(allEntriesStream, filterStream, outputStream, function (er) {
+ if (er) return cb(er)
+ if (!anyOutput && !npm.config.get('json') && !npm.config.get('parseable')) {
+ output('No matches found for ' + (args.map(JSON.stringify).join(' ')))
}
- )
- output = trimToMaxWidth(output)
- output = highlightSearchTerms(output, args)
-
- return output
+ log.silly('search', 'index search completed')
+ log.clearProgress()
+ cb(null, {})
+ })
}
-var colors = [31, 33, 32, 36, 34, 35]
-var cl = colors.length
-
-function addColorMarker (str, arg, i) {
- var m = i % cl + 1
- var markStart = String.fromCharCode(m)
- var markEnd = String.fromCharCode(0)
-
- if (arg.charAt(0) === '/') {
- return str.replace(
- new RegExp(arg.substr(1, arg.length - 2), 'gi'),
- function (bit) { return markStart + bit + markEnd }
- )
- }
-
- // just a normal string, do the split/map thing
- var pieces = str.toLowerCase().split(arg.toLowerCase())
- var p = 0
-
- return pieces.map(function (piece) {
- piece = str.substr(p, piece.length)
- var mark = markStart +
- str.substr(p + piece.length, arg.length) +
- markEnd
- p += piece.length + arg.length
- return piece + mark
- }).join('')
+function prepareIncludes (args, searchopts) {
+ if (typeof searchopts !== 'string') searchopts = ''
+ return searchopts.split(/\s+/).concat(args).map(function (s) {
+ return s.toLowerCase()
+ }).filter(function (s) { return s })
}
-function colorize (line) {
- for (var i = 0; i < cl; i++) {
- var m = i + 1
- var color = npm.color ? '\u001B[' + colors[i] + 'm' : ''
- line = line.split(String.fromCharCode(m)).join(color)
+function prepareExcludes (searchexclude) {
+ var exclude
+ if (typeof searchexclude === 'string') {
+ exclude = searchexclude.split(/\s+/)
+ } else {
+ exclude = []
}
- var uncolor = npm.color ? '\u001B[0m' : ''
- return line.split('\u0000').join(uncolor)
-}
-
-function getMaxWidth () {
- var cols
- try {
- var tty = require('tty')
- var stdout = process.stdout
- cols = !tty.isatty(stdout.fd) ? Infinity : process.stdout.getWindowSize()[0]
- cols = (cols === 0) ? Infinity : cols
- } catch (ex) { cols = Infinity }
- return cols
-}
-
-function trimToMaxWidth (str) {
- var maxWidth = getMaxWidth()
- return str.split('\n').map(function (line) {
- return line.slice(0, maxWidth)
- }).join('\n')
+ return exclude.map(function (s) {
+ return s.toLowerCase()
+ })
}
-function highlightSearchTerms (str, terms) {
- terms.forEach(function (arg, i) {
- str = addColorMarker(str, arg, i)
+function streamFilter (filter) {
+ return ms.through.obj(function (chunk, enc, cb) {
+ if (filter(chunk)) {
+ this.push(chunk)
+ }
+ cb()
})
-
- return colorize(str).trim()
}