Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGar <gar+gh@danger.computer>2022-05-07 19:11:18 +0300
committerGitHub <noreply@github.com>2022-05-07 19:11:18 +0300
commit48d2db6037487fd782f67bbcd2cf12e009ece17b (patch)
treeaf1907ea0d36bfd9d7c5673ae51e4e8b3a4c7760 /lib
parent8e7ea9b61afe37de6017ff77c142ef3abdff6bec (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')
-rw-r--r--lib/commands/completion.js18
-rw-r--r--lib/commands/search.js47
-rw-r--r--lib/commands/view.js3
-rw-r--r--lib/search/package-filter.js43
-rw-r--r--lib/utils/config/definitions.js2
-rw-r--r--lib/utils/file-exists.js10
-rw-r--r--lib/utils/format-bytes.js1
-rw-r--r--lib/utils/format-search-stream.js (renamed from lib/search/format-package-stream.js)66
-rw-r--r--lib/utils/read-package-name.js9
9 files changed, 58 insertions, 141 deletions
diff --git a/lib/commands/completion.js b/lib/commands/completion.js
index 5b7e0d355..c24fb050d 100644
--- a/lib/commands/completion.js
+++ b/lib/commands/completion.js
@@ -29,18 +29,26 @@
// as an array.
//
+const fs = require('@npmcli/fs')
+const nopt = require('nopt')
+
const { definitions, shorthands } = require('../utils/config/index.js')
const { aliases, cmdList, plumbing } = require('../utils/cmd-list.js')
const aliasNames = Object.keys(aliases)
const fullList = cmdList.concat(aliasNames).filter(c => !plumbing.includes(c))
-const nopt = require('nopt')
const configNames = Object.keys(definitions)
const shorthandNames = Object.keys(shorthands)
const allConfs = configNames.concat(shorthandNames)
const { isWindowsShell } = require('../utils/is-windows.js')
-const fileExists = require('../utils/file-exists.js')
+const fileExists = async (file) => {
+ try {
+ const stat = await fs.stat(file)
+ return stat.isFile()
+ } catch {
+ return false
+ }
+}
-const { promisify } = require('util')
const BaseCommand = require('../base-command.js')
class Completion extends BaseCommand {
@@ -189,12 +197,10 @@ class Completion extends BaseCommand {
}
const dumpScript = async () => {
- const fs = require('fs')
- const readFile = promisify(fs.readFile)
const { resolve } = require('path')
const p = resolve(__dirname, '..', 'utils', 'completion.sh')
- const d = (await readFile(p, 'utf8')).replace(/^#!.*?\n/, '')
+ const d = (await fs.readFile(p, 'utf8')).replace(/^#!.*?\n/, '')
await new Promise((res, rej) => {
let done = false
process.stdout.on('error', er => {
diff --git a/lib/commands/search.js b/lib/commands/search.js
index a06ba4031..8751e9e7d 100644
--- a/lib/commands/search.js
+++ b/lib/commands/search.js
@@ -3,26 +3,33 @@ const Pipeline = require('minipass-pipeline')
const libSearch = require('libnpmsearch')
const log = require('../utils/log-shim.js')
-const formatPackageStream = require('../search/format-package-stream.js')
-const packageFilter = require('../search/package-filter.js')
+const formatSearchStream = require('../utils/format-search-stream.js')
+
+function filter (data, include, exclude) {
+ const words = [data.name]
+ .concat(data.maintainers.map(m => `=${m.username}`))
+ .concat(data.keywords || [])
+ .map(f => f && f.trim && f.trim())
+ .filter(f => f)
+ .join(' ')
+ .toLowerCase()
+
+ if (exclude.find(e => match(words, e))) {
+ return false
+ }
-function prepareIncludes (args) {
- return args
- .map(s => s.toLowerCase())
- .filter(s => s)
+ return true
}
-function prepareExcludes (searchexclude) {
- var exclude
- if (typeof searchexclude === 'string') {
- exclude = searchexclude.split(/\s+/)
- } else {
- exclude = []
+function match (words, pattern) {
+ if (pattern.startsWith('/')) {
+ if (pattern.endsWith('/')) {
+ pattern = pattern.slice(0, -1)
+ }
+ pattern = new RegExp(pattern.slice(1))
+ return words.match(pattern)
}
-
- return exclude
- .map(s => s.toLowerCase())
- .filter(s => s)
+ return words.indexOf(pattern) !== -1
}
const BaseCommand = require('../base-command.js')
@@ -50,8 +57,8 @@ class Search extends BaseCommand {
const opts = {
...this.npm.flatOptions,
...this.npm.flatOptions.search,
- include: prepareIncludes(args),
- exclude: prepareExcludes(this.npm.flatOptions.search.exclude),
+ include: args.map(s => s.toLowerCase()).filter(s => s),
+ exclude: this.npm.flatOptions.search.exclude.split(/\s+/),
}
if (opts.include.length === 0) {
@@ -63,7 +70,7 @@ class Search extends BaseCommand {
class FilterStream extends Minipass {
write (pkg) {
- if (packageFilter(pkg, opts.include, opts.exclude)) {
+ if (filter(pkg, opts.include, opts.exclude)) {
super.write(pkg)
}
}
@@ -73,7 +80,7 @@ class Search extends BaseCommand {
// Grab a configured output stream that will spit out packages in the
// desired format.
- const outputStream = formatPackageStream({
+ const outputStream = formatSearchStream({
args, // --searchinclude options are not highlighted
...opts,
})
diff --git a/lib/commands/view.js b/lib/commands/view.js
index 403d09d81..d78ee77dc 100644
--- a/lib/commands/view.js
+++ b/lib/commands/view.js
@@ -57,9 +57,6 @@ class View extends BaseCommand {
function getFields (d, f, pref) {
f = f || []
- if (!d) {
- return f
- }
pref = pref || []
Object.keys(d).forEach((k) => {
if (k.charAt(0) === '_' || k.indexOf('.') !== -1) {
diff --git a/lib/search/package-filter.js b/lib/search/package-filter.js
deleted file mode 100644
index bb0ae679b..000000000
--- a/lib/search/package-filter.js
+++ /dev/null
@@ -1,43 +0,0 @@
-module.exports = filter
-function filter (data, include, exclude, opts) {
- return typeof data === 'object' &&
- filterWords(data, include, exclude, opts)
-}
-
-function getWords (data, opts) {
- return [data.name]
- .concat((opts && opts.description) ? data.description : [])
- .concat((data.maintainers || []).map(m => `=${m.name}`))
- .concat(data.versions && data.versions.length && data.url && ('<' + data.url + '>'))
- .concat(data.keywords || [])
- .map(f => f && f.trim && f.trim())
- .filter(f => f)
- .join(' ')
- .toLowerCase()
-}
-
-function filterWords (data, include, exclude, opts) {
- var words = getWords(data, opts)
- for (var i = 0, l = include.length; i < l; i++) {
- if (!match(words, include[i])) {
- return false
- }
- }
-
- for (i = 0, l = exclude.length; i < l; i++) {
- if (match(words, exclude[i])) {
- return false
- }
- }
-
- return true
-}
-
-function match (words, pattern) {
- if (pattern.charAt(0) === '/') {
- pattern = pattern.replace(/\/$/, '')
- pattern = new RegExp(pattern.slice(1))
- return words.match(pattern)
- }
- return words.indexOf(pattern) !== -1
-}
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/search/format-package-stream.js b/lib/utils/format-search-stream.js
index acead79e1..2a2dadd5c 100644
--- a/lib/search/format-package-stream.js
+++ b/lib/utils/format-search-stream.js
@@ -1,6 +1,3 @@
-// XXX these output classes should not live in here forever. it'd be good to
-// split them out, perhaps to libnpmsearch
-
const Minipass = require('minipass')
const columnify = require('columnify')
@@ -18,32 +15,26 @@ const columnify = require('columnify')
// The returned stream will format this package data
// into a byte stream of formatted, displayable output.
-module.exports = (opts = {}) =>
- opts.json ? new JSONOutputStream() : new TextOutputStream(opts)
+module.exports = (opts) => {
+ return opts.json ? new JSONOutputStream() : new TextOutputStream(opts)
+}
class JSONOutputStream extends Minipass {
- constructor () {
- super()
- this._didFirst = false
- }
+ #didFirst = false
write (obj) {
- if (!this._didFirst) {
+ if (!this.#didFirst) {
super.write('[\n')
- this._didFirst = true
+ this.#didFirst = true
} else {
super.write('\n,\n')
}
- try {
- return super.write(JSON.stringify(obj))
- } catch (er) {
- return this.emit('error', er)
- }
+ return super.write(JSON.stringify(obj))
}
end () {
- super.write(this._didFirst ? ']\n' : '\n[]\n')
+ super.write(this.#didFirst ? ']\n' : '\n[]\n')
super.end()
}
}
@@ -61,14 +52,11 @@ class TextOutputStream extends Minipass {
}
function prettify (data, num, opts) {
- opts = opts || {}
var truncate = !opts.long
var pkg = normalizePackage(data, opts)
- var columns = opts.description
- ? ['name', 'description', 'author', 'date', 'version', 'keywords']
- : ['name', 'author', 'date', 'version', 'keywords']
+ var columns = ['name', 'description', 'author', 'date', 'version', 'keywords']
if (opts.parseable) {
return columns.map(function (col) {
@@ -76,7 +64,10 @@ function prettify (data, num, opts) {
}).join('\t')
}
- var output = columnify(
+ // 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,
@@ -92,8 +83,8 @@ function prettify (data, num, opts) {
keywords: { maxWidth: Infinity },
},
}
- )
- output = trimToMaxWidth(output)
+ ).split('\n').map(line => line.slice(0, maxWidth)).join('\n')
+
if (opts.color) {
output = highlightSearchTerms(output, opts.args)
}
@@ -140,26 +131,6 @@ function colorize (line) {
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')
-}
-
function highlightSearchTerms (str, terms) {
terms.forEach(function (arg, i) {
str = addColorMarker(str, arg, i)
@@ -169,13 +140,10 @@ function highlightSearchTerms (str, terms) {
}
function normalizePackage (data, opts) {
- opts = opts || {}
return {
name: data.name,
- description: opts.description ? data.description : '',
- author: (data.maintainers || []).map(function (m) {
- return '=' + m.username
- }).join(' '),
+ description: data.description,
+ author: data.maintainers.map((m) => `=${m.username}`).join(' '),
keywords: Array.isArray(data.keywords)
? data.keywords.join(' ')
: typeof data.keywords === 'string'
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