From c7787b3fb7630aab84aae83ebf9a7117c7173b6b Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 9 Sep 2021 12:56:36 -0700 Subject: [PATCH 01/16] chore: bundle npm-install-checks This is already part of the published npm, just not in git --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 3459c81ccf190..20b80c7ebe21c 100644 --- a/package.json +++ b/package.json @@ -168,6 +168,7 @@ "node-gyp", "nopt", "npm-audit-report", + "npm-install-checks", "npm-package-arg", "npm-pick-manifest", "npm-profile", From 1fbbe1e04be5d79c7b49910324e64c19ed599eeb Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 9 Sep 2021 13:14:21 -0700 Subject: [PATCH 02/16] chore: bundled npm-install-checks in lockfile too --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index ed4ce37cde425..852dc51752ea5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "node-gyp", "nopt", "npm-audit-report", + "npm-install-checks", "npm-package-arg", "npm-pick-manifest", "npm-profile", From ac8e4ad18a6b726dd2c3abcb0f605701cca0ae2c Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 9 Sep 2021 14:05:14 -0700 Subject: [PATCH 03/16] deps: init-package-json@2.0.5 * fix: bin script path --- node_modules/init-package-json/LICENSE | 15 -- node_modules/init-package-json/LICENSE.md | 18 ++ .../{ => lib}/default-input.js | 177 ++++++++++++------ .../{ => lib}/init-package-json.js | 66 ++++--- node_modules/init-package-json/package.json | 34 ++-- package-lock.json | 24 ++- package.json | 2 +- 7 files changed, 207 insertions(+), 129 deletions(-) delete mode 100644 node_modules/init-package-json/LICENSE create mode 100644 node_modules/init-package-json/LICENSE.md rename node_modules/init-package-json/{ => lib}/default-input.js (64%) rename node_modules/init-package-json/{ => lib}/init-package-json.js (79%) diff --git a/node_modules/init-package-json/LICENSE b/node_modules/init-package-json/LICENSE deleted file mode 100644 index 05eeeb88c2ef4..0000000000000 --- a/node_modules/init-package-json/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) Isaac Z. Schlueter - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/init-package-json/LICENSE.md b/node_modules/init-package-json/LICENSE.md new file mode 100644 index 0000000000000..845be76f64e78 --- /dev/null +++ b/node_modules/init-package-json/LICENSE.md @@ -0,0 +1,18 @@ +ISC License + +Copyright npm, Inc. + +Permission to use, copy, modify, and/or distribute this +software for any purpose with or without fee is hereby +granted, provided that the above copyright notice and this +permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO +EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/init-package-json/default-input.js b/node_modules/init-package-json/lib/default-input.js similarity index 64% rename from node_modules/init-package-json/default-input.js rename to node_modules/init-package-json/lib/default-input.js index d1f65841d6c5a..0003472975760 100644 --- a/node_modules/init-package-json/default-input.js +++ b/node_modules/init-package-json/lib/default-input.js @@ -1,5 +1,5 @@ +/* eslint-disable no-undef */ var fs = require('fs') -var glob = require('glob') var path = require('path') var validateLicense = require('validate-npm-package-license') var validateName = require('validate-npm-package-name') @@ -15,35 +15,57 @@ function niceName (n) { return n.replace(/^node-|[.-]js$/g, '').replace(/\s+/g, ' ').replace(/ /g, '-').toLowerCase() } -function readDeps (test, excluded) { return function (cb) { - fs.readdir('node_modules', function (er, dir) { - if (er) return cb() - var deps = {} - var n = dir.length - if (n === 0) return cb(null, deps) - dir.forEach(function (d) { - if (d.match(/^\./)) return next() - if (test !== isTestPkg(d) || excluded[d]) - return next() - - var dp = path.join(dirname, 'node_modules', d, 'package.json') - fs.readFile(dp, 'utf8', function (er, p) { - if (er) return next() - try { p = JSON.parse(p) } - catch (e) { return next() } - if (!p.version) return next() - if (p._requiredBy) { - if (!p._requiredBy.some(function (req) { return req === '#USER' })) return next() +function readDeps (test, excluded) { + return function (cb) { + fs.readdir('node_modules', function (er, dir) { + if (er) { + return cb() + } + var deps = {} + var n = dir.length + if (n === 0) { + return cb(null, deps) + } + dir.forEach(function (d) { + if (d.match(/^\./)) { + return next() + } + if (test !== isTestPkg(d) || excluded[d]) { + return next() } - deps[d] = config.get('save-exact') ? p.version : config.get('save-prefix') + p.version - return next() + + var dp = path.join(dirname, 'node_modules', d, 'package.json') + fs.readFile(dp, 'utf8', function (er, p) { + if (er) { + return next() + } + try { + p = JSON.parse(p) + } catch (e) { + return next() + } + if (!p.version) { + return next() + } + if (p._requiredBy) { + if (!p._requiredBy.some(function (req) { + return req === '#USER' + })) { + return next() + } + } + deps[d] = config.get('save-exact') ? p.version : config.get('save-prefix') + p.version + return next() + }) }) + function next () { + if (--n === 0) { + return cb(null, deps) + } + } }) - function next () { - if (--n === 0) return cb(null, deps) - } - }) -}} + } +} var name = niceName(package.name || basename) var spec @@ -54,16 +76,20 @@ try { } var scope = config.get('scope') if (scope) { - if (scope.charAt(0) !== '@') scope = '@' + scope + if (scope.charAt(0) !== '@') { + scope = '@' + scope + } if (spec.scope) { name = scope + '/' + spec.name.split('/')[1] } else { name = scope + '/' + name } } -exports.name = yes ? name : prompt('package name', name, function (data) { +exports.name = yes ? name : prompt('package name', name, function (data) { var its = validateName(data) - if (its.validForNewPackages) return data + if (its.validForNewPackages) { + return data + } var errors = (its.errors || []).concat(its.warnings || []) var er = new Error('Sorry, ' + errors.join(' and ') + '.') er.notValid = true @@ -83,7 +109,9 @@ var version = package.version || exports.version = yes ? version : prompt('version', version, function (version) { - if (semver.valid(version)) return version + if (semver.valid(version)) { + return version + } var er = new Error('Invalid version: "' + version + '"') er.notValid = true return er @@ -96,22 +124,25 @@ if (!package.description) { if (!package.main) { exports.main = function (cb) { fs.readdir(dirname, function (er, f) { - if (er) f = [] + if (er) { + f = [] + } f = f.filter(function (f) { return f.match(/\.js$/) }) - if (f.indexOf('index.js') !== -1) + if (f.indexOf('index.js') !== -1) { f = 'index.js' - else if (f.indexOf('main.js') !== -1) + } else if (f.indexOf('main.js') !== -1) { f = 'main.js' - else if (f.indexOf(basename + '.js') !== -1) + } else if (f.indexOf(basename + '.js') !== -1) { f = basename + '.js' - else + } else { f = f[0] + } - var index = f || 'index.js' + var index = f || 'index.js' return cb(null, yes ? index : prompt('entry point', index)) }) } @@ -121,18 +152,24 @@ if (!package.bin) { exports.bin = function (cb) { fs.readdir(path.resolve(dirname, 'bin'), function (er, d) { // no bins - if (er) return cb() + if (er) { + return cb() + } // just take the first js file we find there, or nada - return cb(null, d.filter(function (f) { - return f.match(/\.js$/) - })[0]) + let r = d.find(f => f.match(/\.js$/)) + if (r) { + r = `bin/${r}` + } + return cb(null, r) }) } } exports.directories = function (cb) { fs.readdir(dirname, function (er, dirs) { - if (er) return cb(er) + if (er) { + return cb(er) + } var res = {} dirs.forEach(function (d) { switch (d) { @@ -143,7 +180,9 @@ exports.directories = function (cb) { case 'lib': return res.lib = d } }) - if (Object.keys(res).length === 0) res = undefined + if (Object.keys(res).length === 0) { + res = undefined + } return cb(null, res) }) } @@ -173,13 +212,15 @@ function setupScripts (d, cb) { } if (!s.test || s.test === notest) { var commands = { - 'tap':'tap test/*.js' - , 'expresso':'expresso test' - , 'mocha':'mocha' + tap: 'tap test/*.js', + expresso: 'expresso test', + mocha: 'mocha', } var command Object.keys(commands).forEach(function (k) { - if (d.indexOf(k) !== -1) command = commands[k] + if (d.indexOf(k) !== -1) { + command = commands[k] + } }) var ps = 'test command' if (yes) { @@ -201,12 +242,18 @@ if (!package.repository) { var i = gconf.indexOf('[remote "origin"]') if (i !== -1) { var u = gconf[i + 1] - if (!u.match(/^\s*url =/)) u = gconf[i + 2] - if (!u.match(/^\s*url =/)) u = null - else u = u.replace(/^\s*url = /, '') + if (!u.match(/^\s*url =/)) { + u = gconf[i + 2] + } + if (!u.match(/^\s*url =/)) { + u = null + } else { + u = u.replace(/^\s*url = /, '') + } } - if (u && u.match(/^git@github.com:/)) + if (u && u.match(/^git@github.com:/)) { u = u.replace(/^git@github.com:/, 'https://github.com/') + } return cb(null, yes ? u : prompt('git repository', u)) }) @@ -215,9 +262,15 @@ if (!package.repository) { if (!package.keywords) { exports.keywords = yes ? '' : prompt('keywords', function (s) { - if (!s) return undefined - if (Array.isArray(s)) s = s.join(' ') - if (typeof s !== 'string') return s + if (!s) { + return undefined + } + if (Array.isArray(s)) { + s = s.join(' ') + } + if (typeof s !== 'string') { + return s + } return s.split(/[\s,]+/) }) } @@ -225,15 +278,15 @@ if (!package.keywords) { if (!package.author) { exports.author = config.get('init.author.name') || config.get('init-author-name') - ? { - "name" : config.get('init.author.name') || + ? { + name: config.get('init.author.name') || config.get('init-author-name'), - "email" : config.get('init.author.email') || + email: config.get('init.author.email') || config.get('init-author-email'), - "url" : config.get('init.author.url') || - config.get('init-author-url') + url: config.get('init.author.url') || + config.get('init-author-url'), } - : yes ? '' : prompt('author') + : yes ? '' : prompt('author') } const defaultDottedInitLicense = config && @@ -248,7 +301,9 @@ var license = package.license || 'ISC' exports.license = yes ? license : prompt('license', license, function (data) { var its = validateLicense(data) - if (its.validForNewPackages) return data + if (its.validForNewPackages) { + return data + } var errors = (its.errors || []).concat(its.warnings || []) var er = new Error('Sorry, ' + errors.join(' and ') + '.') er.notValid = true diff --git a/node_modules/init-package-json/init-package-json.js b/node_modules/init-package-json/lib/init-package-json.js similarity index 79% rename from node_modules/init-package-json/init-package-json.js rename to node_modules/init-package-json/lib/init-package-json.js index 83e7342d0aa4f..bee79351caab3 100644 --- a/node_modules/init-package-json/init-package-json.js +++ b/node_modules/init-package-json/lib/init-package-json.js @@ -12,7 +12,6 @@ var read = require('read') // to validate the data object at the end as a worthwhile package // and assign default values for things. -// readJson.extras(file, data, cb) var readJson = require('read-package-json') function yes (conf) { @@ -23,8 +22,10 @@ function yes (conf) { } function init (dir, input, config, cb) { - if (typeof config === 'function') - cb = config, config = {} + if (typeof config === 'function') { + cb = config + config = {} + } // accept either a plain-jane object, or a config object // with a "get" method. @@ -36,7 +37,7 @@ function init (dir, input, config, cb) { }, toJSON: function () { return data - } + }, } } @@ -52,14 +53,18 @@ function init (dir, input, config, cb) { readJson(packageFile, function (er, d) { readJson.extraSet = es - if (er) pkg = {} - else pkg = d + if (er) { + pkg = {} + } else { + pkg = d + } ctx.filename = packageFile ctx.dirname = path.dirname(packageFile) ctx.basename = path.basename(ctx.dirname) - if (!pkg.version || !semver.valid(pkg.version)) + if (!pkg.version || !semver.valid(pkg.version)) { delete pkg.version + } ctx.package = pkg ctx.config = config || {} @@ -71,7 +76,9 @@ function init (dir, input, config, cb) { pz.on('error', cb) pz.on('data', function (data) { Object.keys(data).forEach(function (k) { - if (data[k] !== undefined && data[k] !== null) pkg[k] = data[k] + if (data[k] !== undefined && data[k] !== null) { + pkg[k] = data[k] + } }) // only do a few of these. @@ -81,8 +88,10 @@ function init (dir, input, config, cb) { return fn.name !== 'authors' && fn.name !== 'mans' }) readJson.extras(packageFile, pkg, function (er, pkg) { + if (er) { + return cb(er, pkg) + } readJson.extraSet = es - if (er) return cb(er, pkg) pkg = unParsePeople(pkg) // no need for the readme now. delete pkg.readme @@ -95,13 +104,15 @@ function init (dir, input, config, cb) { delete pkg.gitHead // if the repo is empty, remove it. - if (!pkg.repository) + if (!pkg.repository) { delete pkg.repository + } // readJson filters out empty descriptions, but init-package-json // traditionally leaves them alone - if (!pkg.description) + if (!pkg.description) { pkg.description = data.description + } var d = JSON.stringify(updateDeps(pkg), null, 2) + '\n' function write (yes) { @@ -116,7 +127,7 @@ function init (dir, input, config, cb) { return write(true) } console.log('About to write to %s:\n\n%s\n', packageFile, d) - read({prompt:'Is this OK? ', default: 'yes'}, function (er, ok) { + read({prompt: 'Is this OK? ', default: 'yes'}, function (er, ok) { if (er) { return cb(er) } @@ -129,18 +140,19 @@ function init (dir, input, config, cb) { }) }) }) - } -function updateDeps(depsData) { +function updateDeps (depsData) { // optionalDependencies don't need to be repeated in two places if (depsData.dependencies) { if (depsData.optionalDependencies) { - for (const name of Object.keys(depsData.optionalDependencies)) + for (const name of Object.keys(depsData.optionalDependencies)) { delete depsData.dependencies[name] + } } - if (Object.keys(depsData.dependencies).length === 0) + if (Object.keys(depsData.dependencies).length === 0) { delete depsData.dependencies + } } return depsData @@ -148,21 +160,25 @@ function updateDeps(depsData) { // turn the objects into somewhat more humane strings. function unParsePeople (data) { - if (data.author) data.author = unParsePerson(data.author) - ;["maintainers", "contributors"].forEach(function (set) { - if (!Array.isArray(data[set])) return; + if (data.author) { + data.author = unParsePerson(data.author) + }['maintainers', 'contributors'].forEach(function (set) { + if (!Array.isArray(data[set])) { + return + } data[set] = data[set].map(unParsePerson) }) return data } function unParsePerson (person) { - if (typeof person === "string") return person - var name = person.name || "" + if (typeof person === 'string') { + return person + } + var name = person.name || '' var u = person.url || person.web - var url = u ? (" ("+u+")") : "" + var url = u ? (' (' + u + ')') : '' var e = person.email || person.mail - var email = e ? (" <"+e+">") : "" - return name+email+url + var email = e ? (' <' + e + '>') : '' + return name + email + url } - diff --git a/node_modules/init-package-json/package.json b/node_modules/init-package-json/package.json index 0e07f48f49746..6d642f6cf6879 100644 --- a/node_modules/init-package-json/package.json +++ b/node_modules/init-package-json/package.json @@ -1,41 +1,46 @@ { "name": "init-package-json", - "version": "2.0.4", - "main": "init-package-json.js", + "version": "2.0.5", + "main": "lib/init-package-json.js", "scripts": { "test": "tap", "preversion": "npm test", "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags" + "prepublishOnly": "git push origin --follow-tags", + "lint": "eslint '**/*.js'", + "postlint": "npm-template-check", + "lintfix": "npm run lint -- --fix", + "snap": "tap", + "posttest": "npm run lint" }, "repository": { "type": "git", "url": "https://github.com/npm/init-package-json.git" }, - "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "author": "GitHub Inc.", "license": "ISC", "description": "A node module to get your node module started", "dependencies": { - "glob": "^7.1.1", - "npm-package-arg": "^8.1.2", + "npm-package-arg": "^8.1.5", "promzard": "^0.3.0", "read": "~1.0.1", - "read-package-json": "^4.0.0", + "read-package-json": "^4.1.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" }, "devDependencies": { "@npmcli/config": "^2.1.0", - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2", - "tap": "^14.11.0" + "@npmcli/template-oss": "^1.0.3", + "tap": "^15.0.9" }, "engines": { "node": ">=10" }, "tap": { - "jobs": "1" + "statements": "94", + "branches": "83", + "lines": "94" }, "keywords": [ "init", @@ -48,7 +53,8 @@ "start" ], "files": [ - "default-input.js", - "init-package-json.js" - ] + "bin", + "lib" + ], + "templateVersion": "1.0.3" } diff --git a/package-lock.json b/package-lock.json index 852dc51752ea5..8f4a37801185a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -105,7 +105,7 @@ "graceful-fs": "^4.2.8", "hosted-git-info": "^4.0.2", "ini": "^2.0.0", - "init-package-json": "^2.0.4", + "init-package-json": "^2.0.5", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^2.3.1", "libnpmaccess": "^4.0.2", @@ -3877,16 +3877,15 @@ } }, "node_modules/init-package-json": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.4.tgz", - "integrity": "sha512-gUACSdZYka+VvnF90TsQorC+1joAVWNI724vBNj3RD0LLMeDss2IuzaeiQs0T4YzKs76BPHtrp/z3sn2p+KDTw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.5.tgz", + "integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==", "inBundle": true, "dependencies": { - "glob": "^7.1.1", - "npm-package-arg": "^8.1.2", + "npm-package-arg": "^8.1.5", "promzard": "^0.3.0", "read": "~1.0.1", - "read-package-json": "^4.0.0", + "read-package-json": "^4.1.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" @@ -13318,15 +13317,14 @@ "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" }, "init-package-json": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.4.tgz", - "integrity": "sha512-gUACSdZYka+VvnF90TsQorC+1joAVWNI724vBNj3RD0LLMeDss2IuzaeiQs0T4YzKs76BPHtrp/z3sn2p+KDTw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-2.0.5.tgz", + "integrity": "sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA==", "requires": { - "glob": "^7.1.1", - "npm-package-arg": "^8.1.2", + "npm-package-arg": "^8.1.5", "promzard": "^0.3.0", "read": "~1.0.1", - "read-package-json": "^4.0.0", + "read-package-json": "^4.1.1", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0" diff --git a/package.json b/package.json index 20b80c7ebe21c..8011f238ac2ff 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "graceful-fs": "^4.2.8", "hosted-git-info": "^4.0.2", "ini": "^2.0.0", - "init-package-json": "^2.0.4", + "init-package-json": "^2.0.5", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^2.3.1", "libnpmaccess": "^4.0.2", From 59743972c2ae1d2dd601aaa6c59974c686b1cb29 Mon Sep 17 00:00:00 2001 From: Gar Date: Mon, 13 Sep 2021 10:31:02 -0700 Subject: [PATCH 04/16] fix(did-you-mean): succeed if cwd is not a package The did-you-mean code was trying to parse a local package.json to suggest scripts and bins, which was causing an exception if you ran npm outside of a directory with a valid package.json. This fixes that. PR-URL: https://github.com/npm/cli/pull/3747 Credit: @wraithgar Close: #3747 Reviewed-by: @nlf --- lib/utils/did-you-mean.js | 29 +++++++------- test/lib/utils/did-you-mean.js | 71 ++++++++++++++++++++++------------ 2 files changed, 61 insertions(+), 39 deletions(-) diff --git a/lib/utils/did-you-mean.js b/lib/utils/did-you-mean.js index 0cfdd035255eb..c324253af2406 100644 --- a/lib/utils/did-you-mean.js +++ b/lib/utils/did-you-mean.js @@ -3,25 +3,26 @@ const readJson = require('read-package-json-fast') const { cmdList } = require('./cmd-list.js') const didYouMean = async (npm, path, scmd) => { - const bestCmd = cmdList + let best = cmdList .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && scmd !== cmd) .map(str => ` npm ${str} # ${npm.commands[str].description}`) - const pkg = await readJson(`${path}/package.json`) - const { scripts } = pkg // We would already be suggesting this in `npm x` so omit them here const runScripts = ['stop', 'start', 'test', 'restart'] - const bestRun = Object.keys(scripts || {}) - .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && - !runScripts.includes(cmd)) - .map(str => ` npm run ${str} # run the "${str}" package script`) - - const { bin } = pkg - const bestBin = Object.keys(bin || {}) - .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4) - .map(str => ` npm exec ${str} # run the "${str}" command from either this or a remote npm package`) - - const best = [...bestCmd, ...bestRun, ...bestBin] + try { + const { bin, scripts } = await readJson(`${path}/package.json`) + best = best.concat( + Object.keys(scripts || {}) + .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && + !runScripts.includes(cmd)) + .map(str => ` npm run ${str} # run the "${str}" package script`), + Object.keys(bin || {}) + .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4) + .map(str => ` npm exec ${str} # run the "${str}" command from either this or a remote npm package`) + ) + } catch (_) { + // gracefully ignore not being in a folder w/ a package.json + } if (best.length === 0) return '' diff --git a/test/lib/utils/did-you-mean.js b/test/lib/utils/did-you-mean.js index 15712b665be6e..1285d5300853b 100644 --- a/test/lib/utils/did-you-mean.js +++ b/test/lib/utils/did-you-mean.js @@ -5,34 +5,55 @@ const dym = require('../../../lib/utils/did-you-mean.js') t.test('did-you-mean', t => { npm.load(err => { t.notOk(err) - t.test('nistall', async t => { - const result = await dym(npm, npm.localPrefix, 'nistall') - t.match(result, 'npm install') - }) - t.test('sttest', async t => { - const result = await dym(npm, npm.localPrefix, 'sttest') - t.match(result, 'npm test') - t.match(result, 'npm run posttest') + t.test('with package.json', t => { + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + bin: { + npx: 'exists', + }, + scripts: { + install: 'exists', + posttest: 'exists', + }, + }), + }) + t.test('nistall', async t => { + const result = await dym(npm, testdir, 'nistall') + t.match(result, 'npm install') + }) + t.test('sttest', async t => { + const result = await dym(npm, testdir, 'sttest') + t.match(result, 'npm test') + t.match(result, 'npm run posttest') + }) + t.test('npz', async t => { + const result = await dym(npm, testdir, 'npxx') + t.match(result, 'npm exec npx') + }) + t.test('qwuijbo', async t => { + const result = await dym(npm, testdir, 'qwuijbo') + t.match(result, '') + }) + t.end() }) - t.test('npz', async t => { - const result = await dym(npm, npm.localPrefix, 'npxx') - t.match(result, 'npm exec npx') + t.test('with no package.json', t => { + const testdir = t.testdir({}) + t.test('nistall', async t => { + const result = await dym(npm, testdir, 'nistall') + t.match(result, 'npm install') + }) + t.end() }) - t.test('qwuijbo', async t => { - const result = await dym(npm, npm.localPrefix, 'qwuijbo') - t.match(result, '') + t.test('missing bin and script properties', async t => { + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'missing-bin', + }), + }) + + const result = await dym(npm, testdir, 'nistall') + t.match(result, 'npm install') }) t.end() }) }) - -t.test('missing bin and script properties', async t => { - const path = t.testdir({ - 'package.json': JSON.stringify({ - name: 'missing-bin', - }), - }) - - const result = await dym(npm, path, 'nistall') - t.match(result, 'npm install') -}) From 0320bd77e2a38f48a88e377df4b122fd21043a83 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Mon, 13 Sep 2021 10:53:13 -0700 Subject: [PATCH 05/16] fix(view): Show the correct publish date for versions selected by range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, `npm view npm@^6` would incorrectly report “published over a year from now” for every entry. Now it reports the correct dates. PR-URL: https://github.com/npm/cli/pull/3739 Credit: @andersk Close: #3739 Reviewed-by: @wraithgar --- lib/view.js | 2 +- tap-snapshots/test/lib/view.js.test.cjs | 23 ++++++++++++++++++++--- test/lib/view.js | 12 +++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/view.js b/lib/view.js index f4fc5974eeeca..0124bfb7d3543 100644 --- a/lib/view.js +++ b/lib/view.js @@ -336,7 +336,7 @@ class View extends BaseCommand { email: color.cyan(manifest._npmUser.email), }), modified: !packument.time ? undefined - : color.yellow(relativeDate(packument.time[packument.version])), + : color.yellow(relativeDate(packument.time[manifest.version])), maintainers: (packument.maintainers || []).map((u) => unparsePerson({ name: color.yellow(u.name), email: color.cyan(u.email), diff --git a/tap-snapshots/test/lib/view.js.test.cjs b/tap-snapshots/test/lib/view.js.test.cjs index 27ba7b1eb6927..9ed8334138cf8 100644 --- a/tap-snapshots/test/lib/view.js.test.cjs +++ b/tap-snapshots/test/lib/view.js.test.cjs @@ -82,7 +82,7 @@ dist dist-tags: latest: 1.0.0 -published {TIME} ago +published yesterday ` exports[`test/lib/view.js TAP should log info of package in current working dir specific version > must match snapshot 1`] = ` @@ -99,7 +99,7 @@ dist dist-tags: latest: 1.0.0 -published {TIME} ago +published yesterday ` exports[`test/lib/view.js TAP should log package info package from git > must match snapshot 1`] = ` @@ -302,7 +302,24 @@ dist dist-tags: latest: 1.0.0 -published {TIME} ago +published yesterday +` + +exports[`test/lib/view.js TAP should log package info package with semver range > must match snapshot 1`] = ` + + +blue@1.0.0 | Proprietary | deps: none | versions: 2 + +dist +.tarball:http://hm.blue.com/1.0.0.tgz +.shasum:123 +.integrity:--- +.unpackedSize:1 B + +dist-tags: +latest: 1.0.0 + +published yesterday ` exports[`test/lib/view.js TAP workspaces all workspaces --json > must match snapshot 1`] = ` diff --git a/test/lib/view.js b/test/lib/view.js index 793917adc6476..096ababb29ae8 100644 --- a/test/lib/view.js +++ b/test/lib/view.js @@ -17,6 +17,9 @@ const cleanLogs = () => { console.log = fn } +// 25 hours ago +const yesterday = new Date(Date.now() - 1000 * 60 * 60 * 25) + const packument = (nv, opts) => { if (!opts.fullMetadata) throw new Error('must fetch fullMetadata') @@ -40,7 +43,7 @@ const packument = (nv, opts) => { latest: '1.0.0', }, time: { - '1.0.0': '2019-08-06T16:21:09.842Z', + '1.0.0': yesterday, }, versions: { '1.0.0': { @@ -332,6 +335,13 @@ t.test('should log package info', t => { }) }) + t.test('package with semver range', t => { + view.exec(['blue@^1.0.0'], () => { + t.matchSnapshot(logs) + t.end() + }) + }) + t.test('package with no modified time', t => { viewUnicode.exec(['cyan@1.0.0'], () => { t.matchSnapshot(logs) From e4a5218573583149af795982a39fa64a4116cdab Mon Sep 17 00:00:00 2001 From: Gar Date: Mon, 13 Sep 2021 11:34:24 -0700 Subject: [PATCH 06/16] fix(install.sh): don't remove old npm first The install script will gracefully fail if things don't work. This is especially important for versions of npm that won't work in your current node version. PR-URL: https://github.com/npm/cli/pull/3748 Credit: @wraithgar Close: #3748 Reviewed-by: @isaacs --- scripts/install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 8c0ba3de72f12..cd6ea391cea5d 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -162,8 +162,6 @@ cd "$TMP" \ && curl -qSsL -o npm.tgz "$url" \ && $tar -xzf npm.tgz \ && cd "$TMP"/package \ - && echo "removing existing npm" \ - && "$node" bin/npm-cli.js rm npm -gf --loglevel=silent \ && echo "installing npm@$t" \ && "$node" bin/npm-cli.js install -gf ../npm.tgz \ && cd "$BACK" \ From 291d977e09f5c17fa2ef8fccda6a61a24cb6d590 Mon Sep 17 00:00:00 2001 From: John Gee Date: Tue, 14 Sep 2021 17:56:53 +1200 Subject: [PATCH 07/16] chore: Fix typos in CONTRIBUTING PR-URL: https://github.com/npm/cli/pull/3753 Credit: @shadowspawn Close: #3753 Reviewed-by: @wraithgar --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5ee9b45608eab..33dff2e8e8b9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,4 +63,4 @@ It should be noted that our team does not accept third-party dependency updates/ ### Tools/Automation -Our core team is responsible for the maintaince of the tooling/automation in this project & we ask collaborators to kindle not make changes to these when contributing (ex. `.github/*`, `.eslintrc.json`, `.licensee.json` etc.) +Our core team is responsible for the maintenance of the tooling/automation in this project & we ask collaborators to kindly not make changes to these when contributing (ex. `.github/*`, `.eslintrc.json`, `.licensee.json` etc.) From b4aac345b0a7cdec4d713c5be4daea37330b2b26 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 14 Sep 2021 07:27:36 -0700 Subject: [PATCH 08/16] fix(config): user-agent properly shows ci The way we were flattening user-agent back into itself meant that any values that were dependent on other config items would never be seen, since we have to re-flatten the item for each one it depends on. We also weren't re-flattening the user-agent when setting workspaces or workspace, which were things that affected the final result. This does change the main config value of `user-agent` but not the flattened one. We are not using the main config value anywhere (which is correct). PR-URL: https://github.com/npm/cli/pull/3754 Credit: @wraithgar Close: #3754 Reviewed-by: @nlf --- lib/utils/config/definitions.js | 12 ++++++- smoke-tests/index.js | 40 ++++++++++++++++++++++- smoke-tests/server.js | 8 ++++- tap-snapshots/test/lib/config.js.test.cjs | 4 +-- test/lib/utils/config/definitions.js | 30 ++++++++++++++--- 5 files changed, 85 insertions(+), 9 deletions(-) diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index 092e0fc435cb4..009f60a7bce61 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -2053,10 +2053,14 @@ define('user-agent', { .replace(/\{workspaces\}/gi, inWorkspaces) .replace(/\{ci\}/gi, ciName ? `ci/${ciName}` : '') .trim() + + // We can't clobber the original or else subsequent flattening will fail + // (i.e. when we change the underlying config values) + // obj[key] = flatOptions.userAgent + // user-agent is a unique kind of config item that gets set from a template // and ends up translated. Because of this, the normal "should we set this // to process.env also doesn't work - obj[key] = flatOptions.userAgent process.env.npm_config_user_agent = flatOptions.userAgent }, }) @@ -2140,6 +2144,9 @@ define('workspace', { a workspace which does not yet exist, to create the folder and set it up as a brand new workspace within the project. `, + flatten: (key, obj, flatOptions) => { + definitions['user-agent'].flatten('user-agent', obj, flatOptions) + }, }) define('workspaces', { @@ -2151,6 +2158,9 @@ define('workspaces', { Enable running a command in the context of **all** the configured workspaces. `, + flatten: (key, obj, flatOptions) => { + definitions['user-agent'].flatten('user-agent', obj, flatOptions) + }, }) define('yes', { diff --git a/smoke-tests/index.js b/smoke-tests/index.js index 9235c8960a26a..5e2d5e071ae12 100644 --- a/smoke-tests/index.js +++ b/smoke-tests/index.js @@ -1,8 +1,9 @@ const fs = require('fs') const { promisify } = require('util') const execAsync = promisify(require('child_process').exec) -const { resolve } = require('path') +const { join, resolve } = require('path') const t = require('tap') +const rimraf = promisify(require('rimraf')) const normalizePath = path => path.replace(/[A-Z]:/, '').replace(/\\/g, '/') const cwd = normalizePath(process.cwd()) @@ -47,6 +48,43 @@ const exec = async cmd => { const readFile = filename => String(fs.readFileSync(resolve(localPrefix, filename))) +// this test must come first, its package.json will be destroyed and the one +// created in the next test (npm init) will create a new one that must be +// present for later tests +t.test('npm install sends correct user-agent', async t => { + const pkgPath = join(localPrefix, 'package.json') + const pkgContent = JSON.stringify({ + name: 'smoke-test-workspaces', + workspaces: ['packages/*'], + }) + fs.writeFileSync(pkgPath, pkgContent, { encoding: 'utf8' }) + + const wsRoot = join(localPrefix, 'packages') + fs.mkdirSync(wsRoot) + + const wsPath = join(wsRoot, 'foo') + fs.mkdirSync(wsPath) + + const wsPkgPath = join(wsPath, 'package.json') + const wsContent = JSON.stringify({ + name: 'foo', + }) + fs.writeFileSync(wsPkgPath, wsContent, { encoding: 'utf8' }) + t.teardown(async () => { + await rimraf(`${localPrefix}/*`) + }) + + const cmd = `${npmBin} install fail_reflect_user_agent` + await t.rejects(exec(cmd), { + stderr: /workspaces\/false/, + }, 'workspaces/false is present in output') + + const wsCmd = `${npmBin} install fail_reflect_user_agent --workspaces` + await t.rejects(exec(wsCmd), { + stderr: /workspaces\/true/, + }, 'workspaces/true is present in output') +}) + t.test('npm init', async t => { const cmd = `${npmBin} init -y` const cmdRes = await exec(cmd) diff --git a/smoke-tests/server.js b/smoke-tests/server.js index b864114af64a8..e0ac0c94eb5ab 100644 --- a/smoke-tests/server.js +++ b/smoke-tests/server.js @@ -1,5 +1,5 @@ /* istanbul ignore file */ -const {join, dirname} = require('path') +const {join, dirname, basename} = require('path') const {existsSync, readFileSync, writeFileSync} = require('fs') const PORT = 12345 + (+process.env.TAP_CHILD_ID || 0) const http = require('http') @@ -150,6 +150,12 @@ const startServer = () => new Promise((res, rej) => { } const f = join(__dirname, 'content', join('/', req.url.replace(/@/, '').replace(/%2f/i, '/'))) + // a magic package that causes us to return an error that will be logged + if (basename(f) === 'fail_reflect_user_agent') { + res.setHeader('npm-notice', req.headers['user-agent']) + res.writeHead(404) + return res.end() + } const isCorgi = req.headers.accept.includes('application/vnd.npm.install-v1+json') const file = f + ( isCorgi && existsSync(`${f}.min.json`) ? '.min.json' diff --git a/tap-snapshots/test/lib/config.js.test.cjs b/tap-snapshots/test/lib/config.js.test.cjs index 817f3c173f19e..b21b75cd25e11 100644 --- a/tap-snapshots/test/lib/config.js.test.cjs +++ b/tap-snapshots/test/lib/config.js.test.cjs @@ -146,7 +146,7 @@ exports[`test/lib/config.js TAP config list --json > output matches snapshot 1`] "unicode": false, "update-notifier": true, "usage": false, - "user-agent": "npm/{NPM-VERSION} node/{NODE-VERSION} {PLATFORM} {ARCH} workspaces/false", + "user-agent": "npm/{npm-version} node/{node-version} {platform} {arch} workspaces/{workspaces} {ci}", "version": false, "versions": false, "viewer": "{VIEWER}", @@ -296,7 +296,7 @@ umask = 0 unicode = false update-notifier = true usage = false -user-agent = "npm/{NPM-VERSION} node/{NODE-VERSION} {PLATFORM} {ARCH} workspaces/false" +user-agent = "npm/{npm-version} node/{node-version} {platform} {arch} workspaces/{workspaces} {ci}" ; userconfig = "{HOME}/.npmrc" ; overridden by cli version = false versions = false diff --git a/test/lib/utils/config/definitions.js b/test/lib/utils/config/definitions.js index 65193020d050c..88993303b539c 100644 --- a/test/lib/utils/config/definitions.js +++ b/test/lib/utils/config/definitions.js @@ -747,7 +747,7 @@ t.test('user-agent', t => { definitions['user-agent'].flatten('user-agent', obj, flat) t.equal(flat.userAgent, expectNoCI) t.equal(process.env.npm_config_user_agent, flat.userAgent, 'npm_user_config environment is set') - t.equal(obj['user-agent'], flat.userAgent, 'config user-agent template is translated') + t.not(obj['user-agent'], flat.userAgent, 'config user-agent template is not translated') obj['ci-name'] = 'foo' obj['user-agent'] = definitions['user-agent'].default @@ -755,7 +755,7 @@ t.test('user-agent', t => { definitions['user-agent'].flatten('user-agent', obj, flat) t.equal(flat.userAgent, expectCI) t.equal(process.env.npm_config_user_agent, flat.userAgent, 'npm_user_config environment is set') - t.equal(obj['user-agent'], flat.userAgent, 'config user-agent template is translated') + t.not(obj['user-agent'], flat.userAgent, 'config user-agent template is not translated') delete obj['ci-name'] obj.workspaces = true @@ -764,7 +764,7 @@ t.test('user-agent', t => { definitions['user-agent'].flatten('user-agent', obj, flat) t.equal(flat.userAgent, expectWorkspaces) t.equal(process.env.npm_config_user_agent, flat.userAgent, 'npm_user_config environment is set') - t.equal(obj['user-agent'], flat.userAgent, 'config user-agent template is translated') + t.not(obj['user-agent'], flat.userAgent, 'config user-agent template is not translated') delete obj.workspaces obj.workspace = ['foo'] @@ -772,7 +772,7 @@ t.test('user-agent', t => { definitions['user-agent'].flatten('user-agent', obj, flat) t.equal(flat.userAgent, expectWorkspaces) t.equal(process.env.npm_config_user_agent, flat.userAgent, 'npm_user_config environment is set') - t.equal(obj['user-agent'], flat.userAgent, 'config user-agent template is translated') + t.not(obj['user-agent'], flat.userAgent, 'config user-agent template is not translated') t.end() }) @@ -853,3 +853,25 @@ t.test('package-lock-only', t => { t.strictSame(flat, { packageLock: false, packageLockOnly: false }) t.end() }) + +t.test('workspaces', t => { + const obj = { + workspaces: true, + 'user-agent': definitions['user-agent'].default, + } + const flat = {} + definitions.workspaces.flatten('workspaces', obj, flat) + t.match(flat.userAgent, /workspaces\/true/) + t.end() +}) + +t.test('workspace', t => { + const obj = { + workspace: ['workspace-a'], + 'user-agent': definitions['user-agent'].default, + } + const flat = {} + definitions.workspace.flatten('workspaces', obj, flat) + t.match(flat.userAgent, /workspaces\/true/) + t.end() +}) From b807cd62eabe337e3243415c9870ea36d9289e12 Mon Sep 17 00:00:00 2001 From: Ayush Rawal Date: Sat, 11 Sep 2021 13:36:09 +0530 Subject: [PATCH 09/16] fix(search): return valid json for no results PR-URL: https://github.com/npm/cli/pull/3738 Credit: @AyushRawal Close: #3738 Reviewed-by: @wraithgar --- lib/search/format-package-stream.js | 2 +- test/lib/search.js | 31 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/search/format-package-stream.js b/lib/search/format-package-stream.js index c88df5eb4be04..fb7d81856d63f 100644 --- a/lib/search/format-package-stream.js +++ b/lib/search/format-package-stream.js @@ -42,7 +42,7 @@ class JSONOutputStream extends Minipass { } end () { - super.write(this._didFirst ? ']\n' : '\n]\n') + super.write(this._didFirst ? ']\n' : '\n[]\n') super.end() } } diff --git a/test/lib/search.js b/test/lib/search.js index 510a470f48088..55b584b8aa7dc 100644 --- a/test/lib/search.js +++ b/test/lib/search.js @@ -130,6 +130,37 @@ t.test('search --json', (t) => { src.end() }) +t.test('search --json', (t) => { + const src = new Minipass() + src.objectMode = true + + npm.flatOptions.json = true + config.json = true + const libnpmsearch = { + stream () { + return src + }, + } + + const Search = t.mock('../../lib/search.js', { + ...mocks, + libnpmsearch, + }) + const search = new Search(npm) + + search.exec(['foo'], (err) => { + if (err) + throw err + + t.equal(result, '\n[]\n', 'should have expected empty square brackets') + + config.json = false + t.end() + }) + + src.end() +}) + t.test('search --searchexclude --searchopts', t => { npm.flatOptions.search = { ...flatOptions.search, From 4d93b484abb50e3704fb436db572b93fb36c7ac3 Mon Sep 17 00:00:00 2001 From: Nate Green Date: Wed, 15 Sep 2021 09:58:13 -0400 Subject: [PATCH 10/16] fix(docs): use correct hyperlink to package-json See npm/documentation#36 PR-URL: https://github.com/npm/cli/pull/3759 Credit: @nategreen Close: #3759 Reviewed-by: @wraithgar --- docs/content/using-npm/scripts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/using-npm/scripts.md b/docs/content/using-npm/scripts.md index e033afd30188a..ad32ca6eb234c 100644 --- a/docs/content/using-npm/scripts.md +++ b/docs/content/using-npm/scripts.md @@ -259,7 +259,7 @@ package.json file, then your package scripts would have the in your code with `process.env.npm_package_name` and `process.env.npm_package_version`, and so on for other fields. -See [`package-json.md`](/using-npm/package-json) for more on package configs. +See [`package-json.md`](/configuring-npm/package-json) for more on package configs. #### current lifecycle event From 2def17a3b625b92b40c6185ff4b47e8ed006492c Mon Sep 17 00:00:00 2001 From: Jacob Yacovelli Date: Wed, 15 Sep 2021 10:42:35 -0400 Subject: [PATCH 11/16] fix(install): use configured registry when checking manifest PR-URL: https://github.com/npm/cli/pull/3760 Credit: @yacoman89 Close: #3760 Reviewed-by: @wraithgar --- lib/install.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/install.js b/lib/install.js index 1589ff589c38e..99f75b71384fa 100644 --- a/lib/install.js +++ b/lib/install.js @@ -135,7 +135,8 @@ class Install extends ArboristWorkspaceCmd { // be very strict about engines when trying to update npm itself const npmInstall = args.find(arg => arg.startsWith('npm@') || arg === 'npm') if (isGlobalInstall && npmInstall) { - const npmManifest = await pacote.manifest(npmInstall) + const npmOptions = this.npm.flatOptions + const npmManifest = await pacote.manifest(npmInstall, npmOptions) try { checks.checkEngine(npmManifest, npmManifest.version, process.version) } catch (e) { From 371655a6b0e6664fec67f16cb247cc9f174a5197 Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 15 Sep 2021 13:04:16 -0700 Subject: [PATCH 12/16] deps: minipass@3.1.5 * fix: re-emit 'error' event if missed and new listener added * fix: do not blow up if process is missing --- node_modules/minipass/index.js | 14 ++++++++++++-- node_modules/minipass/package.json | 4 ++-- package-lock.json | 12 ++++++------ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/node_modules/minipass/index.js b/node_modules/minipass/index.js index 56cbd665d2526..ae134a066d77f 100644 --- a/node_modules/minipass/index.js +++ b/node_modules/minipass/index.js @@ -1,4 +1,8 @@ 'use strict' +const proc = typeof process === 'object' && process ? process : { + stdout: null, + stderr: null, +} const EE = require('events') const Stream = require('stream') const Yallist = require('yallist') @@ -8,6 +12,7 @@ const EOF = Symbol('EOF') const MAYBE_EMIT_END = Symbol('maybeEmitEnd') const EMITTED_END = Symbol('emittedEnd') const EMITTING_END = Symbol('emittingEnd') +const EMITTED_ERROR = Symbol('emittedError') const CLOSED = Symbol('closed') const READ = Symbol('read') const FLUSH = Symbol('flush') @@ -66,6 +71,7 @@ module.exports = class Minipass extends Stream { this[EMITTED_END] = false this[EMITTING_END] = false this[CLOSED] = false + this[EMITTED_ERROR] = null this.writable = true this.readable = true this[BUFFERLENGTH] = 0 @@ -310,7 +316,7 @@ module.exports = class Minipass extends Stream { const ended = this[EMITTED_END] opts = opts || {} - if (dest === process.stdout || dest === process.stderr) + if (dest === proc.stdout || dest === proc.stderr) opts.end = false else opts.end = opts.end !== false @@ -339,6 +345,8 @@ module.exports = class Minipass extends Stream { else if (isEndish(ev) && this[EMITTED_END]) { super.emit(ev) this.removeAllListeners(ev) + } else if (ev === 'error' && this[EMITTED_ERROR]) { + fn.call(this, this[EMITTED_ERROR]) } } } @@ -400,6 +408,8 @@ module.exports = class Minipass extends Stream { // don't emit close before 'end' and 'finish' if (!this[EMITTED_END] && !this[DESTROYED]) return + } else if (ev === 'error') { + this[EMITTED_ERROR] = data } // TODO: replace with a spread operator when Node v4 support drops @@ -452,8 +462,8 @@ module.exports = class Minipass extends Stream { promise () { return new Promise((resolve, reject) => { this.on(DESTROYED, () => reject(new Error('stream destroyed'))) - this.on('end', () => resolve()) this.on('error', er => reject(er)) + this.on('end', () => resolve()) }) } diff --git a/node_modules/minipass/package.json b/node_modules/minipass/package.json index 54f62d56d46d8..165fa662ab4a7 100644 --- a/node_modules/minipass/package.json +++ b/node_modules/minipass/package.json @@ -1,6 +1,6 @@ { "name": "minipass", - "version": "3.1.3", + "version": "3.1.5", "description": "minimal implementation of a PassThrough stream", "main": "index.js", "dependencies": { @@ -8,7 +8,7 @@ }, "devDependencies": { "end-of-stream": "^1.4.0", - "tap": "^14.6.5", + "tap": "^15.0.9", "through2": "^2.0.3" }, "scripts": { diff --git a/package-lock.json b/package-lock.json index 8f4a37801185a..be697701ff43b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5114,9 +5114,9 @@ "dev": true }, "node_modules/minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", "inBundle": true, "dependencies": { "yallist": "^4.0.0" @@ -14232,9 +14232,9 @@ "dev": true }, "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", "requires": { "yallist": "^4.0.0" } From ca792acdd4ba683d8415c88188ec6739033fb4fd Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 15 Sep 2021 11:12:49 -0700 Subject: [PATCH 13/16] fix(logs): clean args for failed commands PR-URL: https://github.com/npm/cli/pull/3761 Credit: @wraithgar Close: #3761 Reviewed-by: @lukekarrys --- lib/utils/error-message.js | 2 +- .../test/lib/utils/error-message.js.test.cjs | 34 +++++++++++++++++++ test/lib/utils/error-message.js | 11 ++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/utils/error-message.js b/lib/utils/error-message.js index 6e12bcb918eef..9343d37d54149 100644 --- a/lib/utils/error-message.js +++ b/lib/utils/error-message.js @@ -367,7 +367,7 @@ module.exports = (er, npm) => { detail.push(['signal', er.signal]) if (er.cmd && Array.isArray(er.args)) - detail.push(['command', ...[er.cmd, ...er.args]]) + detail.push(['command', ...[er.cmd, ...er.args.map(replaceInfo)]]) if (er.stdout) detail.push(['', er.stdout.trim()]) diff --git a/tap-snapshots/test/lib/utils/error-message.js.test.cjs b/tap-snapshots/test/lib/utils/error-message.js.test.cjs index 1f73361c48589..79301bfaa0cf0 100644 --- a/tap-snapshots/test/lib/utils/error-message.js.test.cjs +++ b/tap-snapshots/test/lib/utils/error-message.js.test.cjs @@ -180,6 +180,40 @@ Object { } ` +exports[`test/lib/utils/error-message.js TAP args are cleaned > must match snapshot 1`] = ` +Object { + "detail": Array [ + Array [ + "signal", + "SIGYOLO", + ], + Array [ + "command", + "some command", + "a", + "r", + "g", + "s", + "https://evil:***@npmjs.org", + ], + Array [ + "", + "stdout", + ], + Array [ + "", + "stderr", + ], + ], + "summary": Array [ + Array [ + "", + "cmd err", + ], + ], +} +` + exports[`test/lib/utils/error-message.js TAP bad engine with config loaded > must match snapshot 1`] = ` Object { "detail": Array [ diff --git a/test/lib/utils/error-message.js b/test/lib/utils/error-message.js index d1c67a95137c4..6b2b5c9222e77 100644 --- a/test/lib/utils/error-message.js +++ b/test/lib/utils/error-message.js @@ -201,6 +201,17 @@ t.test('default message', t => { t.end() }) +t.test('args are cleaned', t => { + t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), { + cmd: 'some command', + signal: 'SIGYOLO', + args: ['a', 'r', 'g', 's', 'https://evil:password@npmjs.org'], + stdout: 'stdout', + stderr: 'stderr', + }), npm)) + t.end() +}) + t.test('eacces/eperm', t => { const runTest = (windows, loaded, cachePath, cacheDest) => t => { if (windows) From a3bb2a988ea524f5df61bf1db7156a4daa855b4d Mon Sep 17 00:00:00 2001 From: Nathan Fritz Date: Thu, 16 Sep 2021 14:37:32 -0700 Subject: [PATCH 14/16] docs: changelog for v7.24.0 --- CHANGELOG.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c591cd2ac559b..77a926d47c274 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,58 @@ +## v7.24.0 (2021-09-16) + +### FEATURES + +* [`c7787b3fb`](https://github.com/npm/cli/commit/c7787b3fb7630aab84aae83ebf9a7117c7173b6b) + [`1fbbe1e04`](https://github.com/npm/cli/commit/1fbbe1e04be5d79c7b49910324e64c19ed599eeb) + bundled npm-install-checks ([@wraithgar](https://github.com/wraithgar)) + +### BUG FIXES + +* [`0320bd77e`](https://github.com/npm/cli/commit/0320bd77e2a38f48a88e377df4b122fd21043a83) + [#3739](https://github.com/npm/cli/issues/3739) + fix(view): Show the correct publish date for versions selected by range ([@andersk](https://github.com/andersk)) +* [`e4a521857`](https://github.com/npm/cli/commit/e4a5218573583149af795982a39fa64a4116cdab) + [#3748](https://github.com/npm/cli/issues/3748) + fix(install.sh): don't remove old npm first + ([@wraithgar](https://github.com/wraithgar)) +* [`b4aac345b`](https://github.com/npm/cli/commit/b4aac345b0a7cdec4d713c5be4daea37330b2b26) + [#3754](https://github.com/npm/cli/issues/3754) + fix(config): user-agent properly shows ci + ([@wraithgar](https://github.com/wraithgar)) +* [`b807cd62e`](https://github.com/npm/cli/commit/b807cd62eabe337e3243415c9870ea36d9289e12) + [#3738](https://github.com/npm/cli/issues/3738) + fix(search): return valid json for no results + ([@AyushRawal](https://github.com/AyushRawal)) +* [`2def17a3b`](https://github.com/npm/cli/commit/2def17a3b625b92b40c6185ff4b47e8ed006492c) + [#3760](https://github.com/npm/cli/issues/3760) + fix(install): use configured registry when checking manifest + ([@yacoman89](https://github.com/yacoman89)) +* [`ca792acdd`](https://github.com/npm/cli/commit/ca792acdd4ba683d8415c88188ec6739033fb4fd) + [#3761](https://github.com/npm/cli/issues/3761) + fix(logs): clean args for failed commands + ([@wraithgar](https://github.com/wraithgar)) + +### DEPENDENCIES + +* [`59743972c`](https://github.com/npm/cli/commit/59743972c2ae1d2dd601aaa6c59974c686b1cb29) + [#3747](https://github.com/npm/cli/issues/3747) + fix(did-you-mean): succeed if cwd is not a package + ([@wraithgar](https://github.com/wraithgar)) +* [`ac8e4ad18`](https://github.com/npm/cli/commit/ac8e4ad18a6b726dd2c3abcb0f605701cca0ae2c) + `init-package-json@2.0.5`: + * fix: bin script path +* [`371655a6b`](https://github.com/npm/cli/commit/371655a6b0e6664fec67f16cb247cc9f174a5197) + `minipass@3.1.5`: + * fix: re-emit 'error' event if missed and new listener added + * fix: do not blow up if process is missing + +### DOCUMENTATION + +* [`4d93b484a`](https://github.com/npm/cli/commit/4d93b484abb50e3704fb436db572b93fb36c7ac3) + [#3759](https://github.com/npm/cli/issues/3759) + fix(docs): use correct hyperlink to package-json + ([@nategreen](https://github.com/nategreen)) + ## v7.23.0 (2021-09-09) ### FEATURES From 21dd300933c770d44e2123ef673628ffce4de7d3 Mon Sep 17 00:00:00 2001 From: Nathan Fritz Date: Thu, 16 Sep 2021 14:37:47 -0700 Subject: [PATCH 15/16] update AUTHORS --- AUTHORS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AUTHORS b/AUTHORS index c204352764831..fb4e46210eac5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -794,3 +794,8 @@ austincho Nathan Fritz tripu <1016538+tripu@users.noreply.github.com> Matsuuu +Anders Kaseorg +John Gee +Ayush Rawal +Nate Green +Jacob Yacovelli From 2c741900f560fd3ad0d5fa8afe583fbd83c5dbbe Mon Sep 17 00:00:00 2001 From: Nathan Fritz Date: Thu, 16 Sep 2021 14:37:48 -0700 Subject: [PATCH 16/16] 7.24.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index be697701ff43b..38b7892aa4bf8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "7.23.0", + "version": "7.24.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "npm", - "version": "7.23.0", + "version": "7.24.0", "bundleDependencies": [ "@npmcli/arborist", "@npmcli/ci-detect", diff --git a/package.json b/package.json index 8011f238ac2ff..38b45947706dc 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "7.23.0", + "version": "7.24.0", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [