diff options
author | Gar <gar+gh@danger.computer> | 2022-05-07 19:11:18 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-07 19:11:18 +0300 |
commit | 48d2db6037487fd782f67bbcd2cf12e009ece17b (patch) | |
tree | af1907ea0d36bfd9d7c5673ae51e4e8b3a4c7760 /lib/utils | |
parent | 8e7ea9b61afe37de6017ff77c142ef3abdff6bec (diff) |
fix: remove test coverage map (#4862)
Turns out there were three files that still had no test coverage because
of the combination of the mocks in tests and the coverage map. Removing
the map altogether exposed them.
This PR removes the coverage map and fixes test to cover all lines that
were being missed.
While adding coverage to the `npm search` codebase multiple unneeded
guards and at least one bug was found (it was impossible to exclude
searches based on username). These were fixed.
The `npm view` tests were also refactored to use the real npm object.
Finally, a small inlining of lib/utils/file-exists.js was done.
Diffstat (limited to 'lib/utils')
-rw-r--r-- | lib/utils/config/definitions.js | 2 | ||||
-rw-r--r-- | lib/utils/file-exists.js | 10 | ||||
-rw-r--r-- | lib/utils/format-bytes.js | 1 | ||||
-rw-r--r-- | lib/utils/format-search-stream.js | 160 | ||||
-rw-r--r-- | lib/utils/read-package-name.js | 9 |
5 files changed, 162 insertions, 20 deletions
diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index 6f1b1a724..a5eac8c82 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -1856,7 +1856,7 @@ define('searchexclude', { `, flatten (key, obj, flatOptions) { flatOptions.search = flatOptions.search || { limit: 20 } - flatOptions.search.exclude = obj[key] + flatOptions.search.exclude = obj[key].toLowerCase() }, }) diff --git a/lib/utils/file-exists.js b/lib/utils/file-exists.js deleted file mode 100644 index 605472536..000000000 --- a/lib/utils/file-exists.js +++ /dev/null @@ -1,10 +0,0 @@ -const fs = require('fs') -const util = require('util') - -const stat = util.promisify(fs.stat) - -const fileExists = (file) => stat(file) - .then((stat) => stat.isFile()) - .catch(() => false) - -module.exports = fileExists diff --git a/lib/utils/format-bytes.js b/lib/utils/format-bytes.js index d7cf6d144..d293001df 100644 --- a/lib/utils/format-bytes.js +++ b/lib/utils/format-bytes.js @@ -23,6 +23,7 @@ const formatBytes = (bytes, space = true) => { return `${(bytes / 1000000).toFixed(1)}${spacer}MB` } + // GB return `${(bytes / 1000000000).toFixed(1)}${spacer}GB` } diff --git a/lib/utils/format-search-stream.js b/lib/utils/format-search-stream.js new file mode 100644 index 000000000..2a2dadd5c --- /dev/null +++ b/lib/utils/format-search-stream.js @@ -0,0 +1,160 @@ +const Minipass = require('minipass') +const columnify = require('columnify') + +// This module consumes package data in the following format: +// +// { +// name: String, +// description: String, +// maintainers: [{ username: String, email: String }], +// keywords: String | [String], +// version: String, +// date: Date // can be null, +// } +// +// The returned stream will format this package data +// into a byte stream of formatted, displayable output. + +module.exports = (opts) => { + return opts.json ? new JSONOutputStream() : new TextOutputStream(opts) +} + +class JSONOutputStream extends Minipass { + #didFirst = false + + write (obj) { + if (!this.#didFirst) { + super.write('[\n') + this.#didFirst = true + } else { + super.write('\n,\n') + } + + return super.write(JSON.stringify(obj)) + } + + end () { + super.write(this.#didFirst ? ']\n' : '\n[]\n') + super.end() + } +} + +class TextOutputStream extends Minipass { + constructor (opts) { + super() + this._opts = opts + this._line = 0 + } + + write (pkg) { + return super.write(prettify(pkg, ++this._line, this._opts)) + } +} + +function prettify (data, num, opts) { + var truncate = !opts.long + + var pkg = normalizePackage(data, opts) + + var columns = ['name', 'description', 'author', 'date', 'version', 'keywords'] + + if (opts.parseable) { + return columns.map(function (col) { + return pkg[col] && ('' + pkg[col]).replace(/\t/g, ' ') + }).join('\t') + } + + // stdout in tap is never a tty + /* istanbul ignore next */ + const maxWidth = process.stdout.isTTY ? process.stdout.getWindowSize()[0] : Infinity + let output = columnify( + [pkg], + { + include: columns, + showHeaders: num <= 1, + columnSplitter: ' | ', + truncate: truncate, + config: { + name: { minWidth: 25, maxWidth: 25, truncate: false, truncateMarker: '' }, + description: { minWidth: 20, maxWidth: 20 }, + author: { minWidth: 15, maxWidth: 15 }, + date: { maxWidth: 11 }, + version: { minWidth: 8, maxWidth: 8 }, + keywords: { maxWidth: Infinity }, + }, + } + ).split('\n').map(line => line.slice(0, maxWidth)).join('\n') + + if (opts.color) { + output = highlightSearchTerms(output, opts.args) + } + + return output +} + +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.slice(1, -1), 'gi'), + bit => 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.slice(p, p + piece.length) + var mark = markStart + + str.slice(p + piece.length, p + piece.length + arg.length) + + markEnd + p += piece.length + arg.length + return piece + mark + }).join('') +} + +function colorize (line) { + for (var i = 0; i < cl; i++) { + var m = i + 1 + var color = '\u001B[' + colors[i] + 'm' + line = line.split(String.fromCharCode(m)).join(color) + } + var uncolor = '\u001B[0m' + return line.split('\u0000').join(uncolor) +} + +function highlightSearchTerms (str, terms) { + terms.forEach(function (arg, i) { + str = addColorMarker(str, arg, i) + }) + + return colorize(str).trim() +} + +function normalizePackage (data, opts) { + return { + name: data.name, + description: data.description, + author: data.maintainers.map((m) => `=${m.username}`).join(' '), + keywords: Array.isArray(data.keywords) + ? data.keywords.join(' ') + : typeof data.keywords === 'string' + ? data.keywords.replace(/[,\s]+/, ' ') + : '', + version: data.version, + date: (data.date && + (data.date.toISOString() // remove time + .split('T').join(' ') + .replace(/:[0-9]{2}\.[0-9]{3}Z$/, '')) + .slice(0, -5)) || + 'prehistoric', + } +} diff --git a/lib/utils/read-package-name.js b/lib/utils/read-package-name.js deleted file mode 100644 index 7ed159877..000000000 --- a/lib/utils/read-package-name.js +++ /dev/null @@ -1,9 +0,0 @@ -const { resolve } = require('path') -const readJson = require('read-package-json-fast') -async function readLocalPackageName (prefix) { - const filepath = resolve(prefix, 'package.json') - const json = await readJson(filepath) - return json.name -} - -module.exports = readLocalPackageName |