diff --git a/docs/content/commands/npm-install.md b/docs/content/commands/npm-install.md index 06c243f068d13..328d6fc14d9db 100644 --- a/docs/content/commands/npm-install.md +++ b/docs/content/commands/npm-install.md @@ -22,7 +22,7 @@ npm install npm install npm install / -aliases: i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall, add +aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall ``` diff --git a/docs/content/commands/npm-search.md b/docs/content/commands/npm-search.md index db6a12bafabf1..340dea9684d00 100644 --- a/docs/content/commands/npm-search.md +++ b/docs/content/commands/npm-search.md @@ -13,7 +13,7 @@ description: Search for packages ```bash npm search [search terms ...] -aliases: s, se, find +aliases: find, s, se ``` diff --git a/docs/content/commands/npm-uninstall.md b/docs/content/commands/npm-uninstall.md index 8132bf6bc40b6..9316c686d4095 100644 --- a/docs/content/commands/npm-uninstall.md +++ b/docs/content/commands/npm-uninstall.md @@ -13,7 +13,7 @@ description: Remove a package ```bash npm uninstall [<@scope>/]... -aliases: un, unlink, remove, rm, r +aliases: unlink, remove, rm, r, un ``` diff --git a/docs/content/commands/npm-view.md b/docs/content/commands/npm-view.md index 53ca408a01224..b50b4bfb56c5d 100644 --- a/docs/content/commands/npm-view.md +++ b/docs/content/commands/npm-view.md @@ -13,7 +13,7 @@ description: View registry info ```bash npm view [<@scope>/][@] [[.subfield]...] -aliases: v, info, show +aliases: info, show, v ``` diff --git a/lib/cli.js b/lib/cli.js index 6583bd0c00206..7b87b94452ead 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -11,9 +11,25 @@ module.exports = async process => { // so now both broken and unsupported use console, but only broken // will process.exit. It is important to now perform *both* of these // checks as early as possible so the user gets the error message. - const { checkForBrokenNode, checkForUnsupportedNode } = require('./utils/unsupported.js') - checkForBrokenNode() - checkForUnsupportedNode() + const semver = require('semver') + const supported = require('../package.json').engines.node + const knownBroken = '<12.5.0' + + const nodejsVersion = process.version.replace(/-.*$/, '') + /* eslint-disable no-console */ + if (semver.satisfies(nodejsVersion, knownBroken)) { + console.error('ERROR: npm is known not to run on Node.js ' + process.version) + console.error("You'll need to upgrade to a newer Node.js version in order to use this") + console.error('version of npm. You can find the latest version at https://nodejs.org/') + process.exit(1) + } + if (!semver.satisfies(nodejsVersion, supported)) { + console.error('npm does not support Node.js ' + process.version) + console.error('You should probably upgrade to a newer version of node as we') + console.error("can't make any promises that npm will work with this version.") + console.error('You can find the latest version at https://nodejs.org/') + } + /* eslint-enable no-console */ const exitHandler = require('./utils/exit-handler.js') process.on('uncaughtException', exitHandler) diff --git a/lib/commands/bin.js b/lib/commands/bin.js index 07d33167d0d07..4200d5b8ca556 100644 --- a/lib/commands/bin.js +++ b/lib/commands/bin.js @@ -1,6 +1,10 @@ const log = require('../utils/log-shim.js') -const envPath = require('../utils/path.js') const BaseCommand = require('../base-command.js') +// TODO this may not be needed at all. Ignoring because our tests normalize +// process.env.path already +/* istanbul ignore next */ +const path = process.env.path || process.env.Path || process.env.PATH +const { delimiter } = require('path') class Bin extends BaseCommand { static description = 'Display npm bin folder' @@ -11,7 +15,7 @@ class Bin extends BaseCommand { async exec (args) { const b = this.npm.bin this.npm.output(b) - if (this.npm.config.get('global') && !envPath.includes(b)) { + if (this.npm.config.get('global') && !path.split(delimiter).includes(b)) { log.error('bin', '(not in PATH env variable)') } } diff --git a/lib/commands/birthday.js b/lib/commands/birthday.js index e889b39f25377..c7b5b31c54a62 100644 --- a/lib/commands/birthday.js +++ b/lib/commands/birthday.js @@ -2,7 +2,9 @@ const BaseCommand = require('../base-command.js') class Birthday extends BaseCommand { static name = 'birthday' + static description = 'Birthday' static ignoreImplicitWorkspace = true + static isShellout = true async exec () { this.npm.config.set('yes', true) diff --git a/lib/commands/completion.js b/lib/commands/completion.js index 0317753a15aaf..d0c68af6cebfc 100644 --- a/lib/commands/completion.js +++ b/lib/commands/completion.js @@ -30,7 +30,6 @@ // const { definitions, shorthands } = require('../utils/config/index.js') -const deref = require('../utils/deref-command.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)) @@ -38,7 +37,7 @@ 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-shell.js') +const { isWindowsShell } = require('../utils/is-windows.js') const fileExists = require('../utils/file-exists.js') const { promisify } = require('util') @@ -152,7 +151,7 @@ class Completion extends BaseCommand { // check if there's a command already. const cmd = parsed.argv.remain[1] if (!cmd) { - return this.wrap(opts, cmdCompl(opts)) + return this.wrap(opts, cmdCompl(opts, this.npm)) } Object.keys(parsed).forEach(k => this.npm.config.set(k, parsed[k])) @@ -269,13 +268,13 @@ const isFlag = word => { // complete against the npm commands // if they all resolve to the same thing, just return the thing it already is -const cmdCompl = opts => { +const cmdCompl = (opts, npm) => { const matches = fullList.filter(c => c.startsWith(opts.partialWord)) if (!matches.length) { return matches } - const derefs = new Set([...matches.map(c => deref(c))]) + const derefs = new Set([...matches.map(c => npm.deref(c))]) if (derefs.size === 1) { return [...derefs] } diff --git a/lib/commands/exec.js b/lib/commands/exec.js index 6b402c856ab1e..5e6a94296d287 100644 --- a/lib/commands/exec.js +++ b/lib/commands/exec.js @@ -46,6 +46,7 @@ class Exec extends BaseCommand { ] static ignoreImplicitWorkspace = false + static isShellout = true async exec (_args, { locationMsg, path, runPath } = {}) { if (!path) { diff --git a/lib/commands/run-script.js b/lib/commands/run-script.js index 74757e984aeed..a1591c7900b44 100644 --- a/lib/commands/run-script.js +++ b/lib/commands/run-script.js @@ -5,7 +5,7 @@ const { isServerPackage } = runScript const rpj = require('read-package-json-fast') const log = require('../utils/log-shim.js') const didYouMean = require('../utils/did-you-mean.js') -const isWindowsShell = require('../utils/is-windows-shell.js') +const { isWindowsShell } = require('../utils/is-windows.js') const cmdList = [ 'publish', @@ -41,6 +41,7 @@ class RunScript extends BaseCommand { static name = 'run-script' static usage = [' [-- ]'] static ignoreImplicitWorkspace = false + static isShellout = true async completion (opts) { const argv = opts.conf.argv.remain diff --git a/lib/lifecycle-cmd.js b/lib/lifecycle-cmd.js index e2190c2de1c0f..41633a4ba389c 100644 --- a/lib/lifecycle-cmd.js +++ b/lib/lifecycle-cmd.js @@ -4,6 +4,7 @@ const BaseCommand = require('./base-command.js') class LifecycleCmd extends BaseCommand { static usage = ['[-- ]'] + static isShellout = true async exec (args, cb) { return this.npm.exec('run-script', [this.constructor.name, ...args]) diff --git a/lib/npm.js b/lib/npm.js index 4cd1d05b373ec..74825c97c2355 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -6,13 +6,11 @@ const Config = require('@npmcli/config') require('graceful-fs').gracefulify(require('fs')) const { definitions, flatten, shorthands } = require('./utils/config/index.js') -const { shellouts } = require('./utils/cmd-list.js') const usage = require('./utils/npm-usage.js') const which = require('which') const fs = require('@npmcli/fs') -const deref = require('./utils/deref-command.js') const LogFile = require('./utils/log-file.js') const Timers = require('./utils/timers.js') const Display = require('./utils/display.js') @@ -20,6 +18,7 @@ const log = require('./utils/log-shim') const replaceInfo = require('./utils/replace-info.js') const updateNotifier = require('./utils/update-notifier.js') const pkg = require('../package.json') +const cmdList = require('./utils/cmd-list.js') let warnedNonDashArg = false const _load = Symbol('_load') @@ -32,7 +31,6 @@ class Npm extends EventEmitter { command = null updateNotification = null loadErr = null - deref = deref argv = [] #loadPromise = null @@ -62,8 +60,24 @@ class Npm extends EventEmitter { return this.constructor.version } - get shelloutCommands () { - return shellouts + deref (c) { + if (!c) { + return + } + if (c.match(/[A-Z]/)) { + c = c.replace(/([A-Z])/g, m => '-' + m.toLowerCase()) + } + if (cmdList.plumbing.indexOf(c) !== -1) { + return c + } + // first deref the abbrev, if there is one + // then resolve any aliases + // so `npm install-cl` will resolve to `install-clean` then to `ci` + let a = cmdList.abbrevs[c] + while (cmdList.aliases[a]) { + a = cmdList.aliases[a] + } + return a } // Get an instantiated npm command @@ -92,6 +106,7 @@ class Npm extends EventEmitter { if (!this.command) { process.env.npm_command = command.name this.command = command.name + this.commandInstance = command } // this is async but we dont await it, since its ok if it doesnt diff --git a/lib/utils/cmd-list.js b/lib/utils/cmd-list.js index b3089a62c60d2..c1d20186a82a6 100644 --- a/lib/utils/cmd-list.js +++ b/lib/utils/cmd-list.js @@ -1,5 +1,23 @@ -// short names for common things -const shorthands = { +const abbrev = require('abbrev') + +// plumbing should not have any aliases +const aliases = { + + // aliases + login: 'adduser', + author: 'owner', + home: 'docs', + issues: 'bugs', + info: 'view', + show: 'view', + find: 'search', + add: 'install', + unlink: 'uninstall', + remove: 'uninstall', + rm: 'uninstall', + r: 'uninstall', + + // short names for common things un: 'uninstall', rb: 'rebuild', list: 'ls', @@ -21,12 +39,11 @@ const shorthands = { 'clean-install-test': 'cit', x: 'exec', why: 'explain', -} - -const affordances = { la: 'll', verison: 'version', ic: 'ci', + + // typos innit: 'init', // manually abbrev so that install-test doesn't make insta stop working in: 'install', @@ -44,119 +61,90 @@ const affordances = { 'dist-tags': 'dist-tag', upgrade: 'update', udpate: 'update', - login: 'adduser', - 'add-user': 'adduser', - author: 'owner', - home: 'docs', - issues: 'bugs', - info: 'view', - show: 'view', - find: 'search', - add: 'install', - unlink: 'uninstall', - remove: 'uninstall', - rm: 'uninstall', - r: 'uninstall', rum: 'run-script', sit: 'cit', urn: 'run-script', ogr: 'org', + 'add-user': 'adduser', } // these are filenames in . +// Keep these sorted so that lib/utils/npm-usage.js outputs in order const cmdList = [ - 'ci', - 'install-ci-test', - 'install', - 'install-test', - 'uninstall', + 'access', + 'adduser', + 'audit', + 'bin', + 'bugs', 'cache', + 'ci', + 'completion', 'config', - 'set', - 'get', - 'update', - 'outdated', - 'prune', - 'pack', - 'find-dupes', 'dedupe', + 'deprecate', + 'diff', + 'dist-tag', + 'docs', + 'doctor', + 'edit', + 'exec', + 'explain', + 'explore', + 'find-dupes', + 'fund', + 'get', + 'help', 'hook', - - 'rebuild', + 'init', + 'install', + 'install-ci-test', + 'install-test', 'link', - - 'publish', - 'star', - 'stars', - 'unstar', - 'adduser', + 'll', 'login', // This is an alias for `adduser` but it can be confusing 'logout', - 'unpublish', - 'owner', - 'access', - 'team', - 'deprecate', - 'shrinkwrap', - 'token', - 'profile', - 'audit', - 'fund', - 'org', - - 'help', 'ls', - 'll', - 'search', - 'view', - 'init', - 'version', - 'edit', - 'explore', - 'docs', - 'repo', - 'bugs', - 'root', - 'prefix', - 'bin', - 'whoami', - 'diff', - 'dist-tag', + 'org', + 'outdated', + 'owner', + 'pack', 'ping', 'pkg', - - 'test', - 'stop', - 'start', + 'prefix', + 'profile', + 'prune', + 'publish', + 'rebuild', + 'repo', 'restart', + 'root', 'run-script', + 'search', + 'set', 'set-script', - 'completion', - 'doctor', - 'exec', - 'explain', -] - -const plumbing = ['birthday', 'help-search'] - -// these commands just shell out to something else or handle the -// error themselves, so it's confusing and weird to write out -// our full error log banner when they exit non-zero -const shellouts = [ - 'exec', - 'run-script', - 'test', + 'shrinkwrap', + 'star', + 'stars', 'start', 'stop', - 'restart', - 'birthday', + 'team', + 'test', + 'token', + 'uninstall', + 'unpublish', + 'unstar', + 'update', + 'version', + 'view', + 'whoami', ] +const plumbing = ['birthday', 'help-search'] +const abbrevs = abbrev(cmdList.concat(Object.keys(aliases))) + module.exports = { - aliases: Object.assign({}, shorthands, affordances), - shorthands, - affordances, + abbrevs, + aliases, cmdList, plumbing, - shellouts, } diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index 04da7f607e709..efc1f72a02059 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -7,7 +7,7 @@ const { version: npmVersion } = require('../../../package.json') const ciDetect = require('@npmcli/ci-detect') const ciName = ciDetect() const querystring = require('querystring') -const isWindows = require('../is-windows.js') +const { isWindows } = require('../is-windows.js') const { join } = require('path') // used by cafile flattening to flatOptions.ca diff --git a/lib/utils/deref-command.js b/lib/utils/deref-command.js deleted file mode 100644 index 0a3c8c90bc903..0000000000000 --- a/lib/utils/deref-command.js +++ /dev/null @@ -1,31 +0,0 @@ -// de-reference abbreviations and shorthands into canonical command name - -const { aliases, cmdList, plumbing } = require('./cmd-list.js') -const aliasNames = Object.keys(aliases) -const fullList = cmdList.concat(aliasNames).filter(c => !plumbing.includes(c)) -const abbrev = require('abbrev') -const abbrevs = abbrev(fullList) - -module.exports = c => { - if (!c || typeof c !== 'string') { - return '' - } - - if (c.match(/[A-Z]/)) { - c = c.replace(/([A-Z])/g, m => '-' + m.toLowerCase()) - } - - if (plumbing.indexOf(c) !== -1) { - return c - } - - // first deref the abbrev, if there is one - // then resolve any aliases - // so `npm install-cl` will resolve to `install-clean` then to `ci` - let a = abbrevs[c] - while (aliases[a]) { - a = aliases[a] - } - - return a || '' -} diff --git a/lib/utils/error-message.js b/lib/utils/error-message.js index 5fa361efcd3da..adf10a56f6d66 100644 --- a/lib/utils/error-message.js +++ b/lib/utils/error-message.js @@ -60,7 +60,7 @@ module.exports = (er, npm) => { npm.config.loaded && er.dest.startsWith(npm.config.get('cache')) - const isWindows = require('./is-windows.js') + const { isWindows } = require('./is-windows.js') if (!isWindows && (isCachePath || isCacheDest)) { // user probably doesn't need this, but still add it to the debug log diff --git a/lib/utils/exit-handler.js b/lib/utils/exit-handler.js index f96d162ce9753..d8ae9994dfecc 100644 --- a/lib/utils/exit-handler.js +++ b/lib/utils/exit-handler.js @@ -144,7 +144,7 @@ const exitHandler = err => { // will presumably print its own errors and exit with a proper status // code if there's a problem. If we got an error with a code=0, then... // something else went wrong along the way, so maybe an npm problem? - const isShellout = npm.shelloutCommands.includes(npm.command) + const isShellout = npm.commandInstance && npm.commandInstance.constructor.isShellout const quietShellout = isShellout && typeof err.code === 'number' && err.code if (quietShellout) { exitCode = err.code diff --git a/lib/utils/is-windows-bash.js b/lib/utils/is-windows-bash.js deleted file mode 100644 index 0ae99e212cc08..0000000000000 --- a/lib/utils/is-windows-bash.js +++ /dev/null @@ -1,3 +0,0 @@ -const isWindows = require('./is-windows.js') -module.exports = isWindows && - (/^MINGW(32|64)$/.test(process.env.MSYSTEM) || process.env.TERM === 'cygwin') diff --git a/lib/utils/is-windows-shell.js b/lib/utils/is-windows-shell.js deleted file mode 100644 index 477bd43cc10cc..0000000000000 --- a/lib/utils/is-windows-shell.js +++ /dev/null @@ -1,3 +0,0 @@ -const isWindows = require('./is-windows.js') -const isWindowsBash = require('./is-windows-bash.js') -module.exports = isWindows && !isWindowsBash diff --git a/lib/utils/is-windows.js b/lib/utils/is-windows.js index fbece90ad7496..57f6599b6ae19 100644 --- a/lib/utils/is-windows.js +++ b/lib/utils/is-windows.js @@ -1 +1,6 @@ -module.exports = process.platform === 'win32' +const isWindows = process.platform === 'win32' +const isWindowsShell = isWindows && + !/^MINGW(32|64)$/.test(process.env.MSYSTEM) && process.env.TERM !== 'cygwin' + +exports.isWindows = isWindows +exports.isWindowsShell = isWindowsShell diff --git a/lib/utils/npm-usage.js b/lib/utils/npm-usage.js index b0c98b2ae6c0b..8d31f0155098b 100644 --- a/lib/utils/npm-usage.js +++ b/lib/utils/npm-usage.js @@ -45,7 +45,7 @@ const wrap = (arr) => { : Math.min(60, Math.max(process.stdout.columns - 16, 24)) let l = 0 - for (const c of arr.sort((a, b) => a < b ? -1 : 1)) { + for (const c of arr) { if (out[l].length + c.length + 2 < line) { out[l] += ', ' + c } else { diff --git a/lib/utils/path.js b/lib/utils/path.js deleted file mode 100644 index ad0065a2c52f3..0000000000000 --- a/lib/utils/path.js +++ /dev/null @@ -1,4 +0,0 @@ -// return the PATH array in a cross-platform way -const PATH = process.env.PATH || process.env.Path || process.env.path -const { delimiter } = require('path') -module.exports = PATH.split(delimiter) diff --git a/lib/utils/unsupported.js b/lib/utils/unsupported.js deleted file mode 100644 index 75aad5e780ec4..0000000000000 --- a/lib/utils/unsupported.js +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-disable no-console */ -const semver = require('semver') -const supported = require('../../package.json').engines.node -const knownBroken = '<6.2.0 || 9 <9.3.0' - -// Keep this file compatible with all practical versions of node -// so we dont get syntax errors when trying to give the users -// a nice error message. Don't use our log handler because -// if we encounter a syntax error early on, that will never -// get displayed to the user. - -const checkVersion = exports.checkVersion = version => { - const versionNoPrerelease = version.replace(/-.*$/, '') - return { - version: versionNoPrerelease, - broken: semver.satisfies(versionNoPrerelease, knownBroken), - unsupported: !semver.satisfies(versionNoPrerelease, supported), - } -} - -exports.checkForBrokenNode = () => { - const nodejs = checkVersion(process.version) - if (nodejs.broken) { - console.error('ERROR: npm is known not to run on Node.js ' + process.version) - console.error("You'll need to upgrade to a newer Node.js version in order to use this") - console.error('version of npm. You can find the latest version at https://nodejs.org/') - process.exit(1) - } -} - -exports.checkForUnsupportedNode = () => { - const nodejs = checkVersion(process.version) - if (nodejs.unsupported) { - console.error('npm does not support Node.js ' + process.version) - console.error('You should probably upgrade to a newer version of node as we') - console.error("can't make any promises that npm will work with this version.") - console.error('You can find the latest version at https://nodejs.org/') - } -} diff --git a/tap-snapshots/test/lib/commands/completion.js.test.cjs b/tap-snapshots/test/lib/commands/completion.js.test.cjs index 4fa3a2179e6ee..232cfec669778 100644 --- a/tap-snapshots/test/lib/commands/completion.js.test.cjs +++ b/tap-snapshots/test/lib/commands/completion.js.test.cjs @@ -44,72 +44,84 @@ exports[`test/lib/commands/completion.js TAP completion double dashes escape fro Array [ Array [ String( - ci - install-ci-test - install - install-test - uninstall + access + adduser + audit + bin + bugs cache + ci + completion config - set - get - update - outdated - prune - pack - find-dupes dedupe + deprecate + diff + dist-tag + docs + doctor + edit + exec + explain + explore + find-dupes + fund + get + help hook - rebuild + init + install + install-ci-test + install-test link - publish - star - stars - unstar - adduser + ll login logout - unpublish - owner - access - team - deprecate - shrinkwrap - token - profile - audit - fund - org - help ls - ll - search - view - init - version - edit - explore - docs - repo - bugs - root - prefix - bin - whoami - diff - dist-tag + org + outdated + owner + pack ping pkg - test - stop - start + prefix + profile + prune + publish + rebuild + repo restart + root run-script + search + set set-script - completion - doctor - exec - explain + shrinkwrap + star + stars + start + stop + team + test + token + uninstall + unpublish + unstar + update + version + view + whoami + login + author + home + issues + info + show + find + add + unlink + remove + rm + r un rb list @@ -150,23 +162,11 @@ Array [ dist-tags upgrade udpate - login - add-user - author - home - issues - info - show - find - add - unlink - remove - rm - r rum sit urn ogr + add-user ), ], ] @@ -198,12 +198,12 @@ exports[`test/lib/commands/completion.js TAP completion multiple command names > Array [ Array [ String( - adduser access + adduser audit - add-user author add + add-user ), ], ] diff --git a/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/tap-snapshots/test/lib/load-all-commands.js.test.cjs index 66c48983a0ea3..0ad87b945fce7 100644 --- a/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -68,6 +68,15 @@ Options: Run "npm help bin" for more info ` +exports[`test/lib/load-all-commands.js TAP load each command birthday > must match snapshot 1`] = ` +Birthday + +Usage: +npm birthday + +Run "npm help birthday" for more info +` + exports[`test/lib/load-all-commands.js TAP load each command bugs > must match snapshot 1`] = ` Report bugs for a package in a web browser @@ -348,6 +357,18 @@ alias: hlep Run "npm help help" for more info ` +exports[`test/lib/load-all-commands.js TAP load each command help-search > must match snapshot 1`] = ` +Search npm help documentation + +Usage: +npm help-search + +Options: +[-l|--long] + +Run "npm help help-search" for more info +` + exports[`test/lib/load-all-commands.js TAP load each command hook > must match snapshot 1`] = ` Manage registry hooks @@ -405,7 +426,7 @@ Options: [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] -aliases: i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall, add +aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall Run "npm help install" for more info ` @@ -763,7 +784,7 @@ Options: [--no-description] [--searchopts ] [--searchexclude ] [--registry ] [--prefer-online] [--prefer-offline] [--offline] -aliases: s, se, find +aliases: find, s, se Run "npm help search" for more info ` @@ -903,7 +924,7 @@ Options: [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] -aliases: un, unlink, remove, rm, r +aliases: unlink, remove, rm, r, un Run "npm help uninstall" for more info ` @@ -981,7 +1002,7 @@ Options: [--json] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] -aliases: v, info, show +aliases: info, show, v Run "npm help view" for more info ` diff --git a/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs b/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs index f842e689f1631..9413f8e9a6d52 100644 --- a/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs +++ b/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs @@ -7,43 +7,348 @@ 'use strict' exports[`test/lib/utils/cmd-list.js TAP > must match snapshot 1`] = ` Object { - "affordances": Object { - "add": "install", - "add-user": "adduser", - "author": "owner", - "dist-tags": "dist-tag", - "find": "search", - "hlep": "help", - "home": "docs", - "ic": "ci", - "in": "install", - "info": "view", - "innit": "init", - "ins": "install", - "inst": "install", - "insta": "install", - "instal": "install", - "install-clean": "ci", - "isnt": "install", - "isnta": "install", - "isntal": "install", - "isntall": "install", - "isntall-clean": "ci", - "issues": "bugs", - "la": "ll", - "login": "adduser", - "ogr": "org", - "r": "uninstall", - "remove": "uninstall", - "rm": "uninstall", - "rum": "run-script", - "show": "view", - "sit": "cit", - "udpate": "update", - "unlink": "uninstall", - "upgrade": "update", - "urn": "run-script", - "verison": "version", + "abbrevs": Object { + "ac": "access", + "acc": "access", + "acce": "access", + "acces": "access", + "access": "access", + "add": "add", + "add-": "add-user", + "add-u": "add-user", + "add-us": "add-user", + "add-use": "add-user", + "add-user": "add-user", + "addu": "adduser", + "addus": "adduser", + "adduse": "adduser", + "adduser": "adduser", + "aud": "audit", + "audi": "audit", + "audit": "audit", + "aut": "author", + "auth": "author", + "autho": "author", + "author": "author", + "bi": "bin", + "bin": "bin", + "bu": "bugs", + "bug": "bugs", + "bugs": "bugs", + "c": "c", + "ca": "cache", + "cac": "cache", + "cach": "cache", + "cache": "cache", + "ci": "ci", + "cit": "cit", + "clean-install": "clean-install", + "clean-install-": "clean-install-test", + "clean-install-t": "clean-install-test", + "clean-install-te": "clean-install-test", + "clean-install-tes": "clean-install-test", + "clean-install-test": "clean-install-test", + "com": "completion", + "comp": "completion", + "compl": "completion", + "comple": "completion", + "complet": "completion", + "completi": "completion", + "completio": "completion", + "completion": "completion", + "con": "config", + "conf": "config", + "confi": "config", + "config": "config", + "cr": "create", + "cre": "create", + "crea": "create", + "creat": "create", + "create": "create", + "dd": "ddp", + "ddp": "ddp", + "ded": "dedupe", + "dedu": "dedupe", + "dedup": "dedupe", + "dedupe": "dedupe", + "dep": "deprecate", + "depr": "deprecate", + "depre": "deprecate", + "deprec": "deprecate", + "depreca": "deprecate", + "deprecat": "deprecate", + "deprecate": "deprecate", + "dif": "diff", + "diff": "diff", + "dist-tag": "dist-tag", + "dist-tags": "dist-tags", + "docs": "docs", + "doct": "doctor", + "docto": "doctor", + "doctor": "doctor", + "ed": "edit", + "edi": "edit", + "edit": "edit", + "exe": "exec", + "exec": "exec", + "expla": "explain", + "explai": "explain", + "explain": "explain", + "explo": "explore", + "explor": "explore", + "explore": "explore", + "find": "find", + "find-": "find-dupes", + "find-d": "find-dupes", + "find-du": "find-dupes", + "find-dup": "find-dupes", + "find-dupe": "find-dupes", + "find-dupes": "find-dupes", + "fu": "fund", + "fun": "fund", + "fund": "fund", + "g": "get", + "ge": "get", + "get": "get", + "he": "help", + "hel": "help", + "help": "help", + "hl": "hlep", + "hle": "hlep", + "hlep": "hlep", + "hom": "home", + "home": "home", + "hoo": "hook", + "hook": "hook", + "i": "i", + "ic": "ic", + "in": "in", + "inf": "info", + "info": "info", + "ini": "init", + "init": "init", + "inn": "innit", + "inni": "innit", + "innit": "innit", + "ins": "ins", + "inst": "inst", + "insta": "insta", + "instal": "instal", + "install": "install", + "install-ci": "install-ci-test", + "install-ci-": "install-ci-test", + "install-ci-t": "install-ci-test", + "install-ci-te": "install-ci-test", + "install-ci-tes": "install-ci-test", + "install-ci-test": "install-ci-test", + "install-cl": "install-clean", + "install-cle": "install-clean", + "install-clea": "install-clean", + "install-clean": "install-clean", + "install-t": "install-test", + "install-te": "install-test", + "install-tes": "install-test", + "install-test": "install-test", + "isnt": "isnt", + "isnta": "isnta", + "isntal": "isntal", + "isntall": "isntall", + "isntall-": "isntall-clean", + "isntall-c": "isntall-clean", + "isntall-cl": "isntall-clean", + "isntall-cle": "isntall-clean", + "isntall-clea": "isntall-clean", + "isntall-clean": "isntall-clean", + "iss": "issues", + "issu": "issues", + "issue": "issues", + "issues": "issues", + "it": "it", + "la": "la", + "lin": "link", + "link": "link", + "lis": "list", + "list": "list", + "ll": "ll", + "ln": "ln", + "logi": "login", + "login": "login", + "logo": "logout", + "logou": "logout", + "logout": "logout", + "ls": "ls", + "og": "ogr", + "ogr": "ogr", + "or": "org", + "org": "org", + "ou": "outdated", + "out": "outdated", + "outd": "outdated", + "outda": "outdated", + "outdat": "outdated", + "outdate": "outdated", + "outdated": "outdated", + "ow": "owner", + "own": "owner", + "owne": "owner", + "owner": "owner", + "pa": "pack", + "pac": "pack", + "pack": "pack", + "pi": "ping", + "pin": "ping", + "ping": "ping", + "pk": "pkg", + "pkg": "pkg", + "pre": "prefix", + "pref": "prefix", + "prefi": "prefix", + "prefix": "prefix", + "pro": "profile", + "prof": "profile", + "profi": "profile", + "profil": "profile", + "profile": "profile", + "pru": "prune", + "prun": "prune", + "prune": "prune", + "pu": "publish", + "pub": "publish", + "publ": "publish", + "publi": "publish", + "publis": "publish", + "publish": "publish", + "r": "r", + "rb": "rb", + "reb": "rebuild", + "rebu": "rebuild", + "rebui": "rebuild", + "rebuil": "rebuild", + "rebuild": "rebuild", + "rem": "remove", + "remo": "remove", + "remov": "remove", + "remove": "remove", + "rep": "repo", + "repo": "repo", + "res": "restart", + "rest": "restart", + "resta": "restart", + "restar": "restart", + "restart": "restart", + "rm": "rm", + "ro": "root", + "roo": "root", + "root": "root", + "rum": "rum", + "run": "run", + "run-": "run-script", + "run-s": "run-script", + "run-sc": "run-script", + "run-scr": "run-script", + "run-scri": "run-script", + "run-scrip": "run-script", + "run-script": "run-script", + "s": "s", + "se": "se", + "sea": "search", + "sear": "search", + "searc": "search", + "search": "search", + "set": "set", + "set-": "set-script", + "set-s": "set-script", + "set-sc": "set-script", + "set-scr": "set-script", + "set-scri": "set-script", + "set-scrip": "set-script", + "set-script": "set-script", + "sho": "show", + "show": "show", + "shr": "shrinkwrap", + "shri": "shrinkwrap", + "shrin": "shrinkwrap", + "shrink": "shrinkwrap", + "shrinkw": "shrinkwrap", + "shrinkwr": "shrinkwrap", + "shrinkwra": "shrinkwrap", + "shrinkwrap": "shrinkwrap", + "si": "sit", + "sit": "sit", + "star": "star", + "stars": "stars", + "start": "start", + "sto": "stop", + "stop": "stop", + "t": "t", + "tea": "team", + "team": "team", + "tes": "test", + "test": "test", + "to": "token", + "tok": "token", + "toke": "token", + "token": "token", + "ts": "tst", + "tst": "tst", + "ud": "udpate", + "udp": "udpate", + "udpa": "udpate", + "udpat": "udpate", + "udpate": "udpate", + "un": "un", + "uni": "uninstall", + "unin": "uninstall", + "unins": "uninstall", + "uninst": "uninstall", + "uninsta": "uninstall", + "uninstal": "uninstall", + "uninstall": "uninstall", + "unl": "unlink", + "unli": "unlink", + "unlin": "unlink", + "unlink": "unlink", + "unp": "unpublish", + "unpu": "unpublish", + "unpub": "unpublish", + "unpubl": "unpublish", + "unpubli": "unpublish", + "unpublis": "unpublish", + "unpublish": "unpublish", + "uns": "unstar", + "unst": "unstar", + "unsta": "unstar", + "unstar": "unstar", + "up": "up", + "upd": "update", + "upda": "update", + "updat": "update", + "update": "update", + "upg": "upgrade", + "upgr": "upgrade", + "upgra": "upgrade", + "upgrad": "upgrade", + "upgrade": "upgrade", + "ur": "urn", + "urn": "urn", + "v": "v", + "veri": "verison", + "veris": "verison", + "veriso": "verison", + "verison": "verison", + "vers": "version", + "versi": "version", + "versio": "version", + "version": "version", + "vi": "view", + "vie": "view", + "view": "view", + "who": "whoami", + "whoa": "whoami", + "whoam": "whoami", + "whoami": "whoami", + "why": "why", + "x": "x", }, "aliases": Object { "add": "install", @@ -105,108 +410,76 @@ Object { "x": "exec", }, "cmdList": Array [ - "ci", - "install-ci-test", - "install", - "install-test", - "uninstall", + "access", + "adduser", + "audit", + "bin", + "bugs", "cache", + "ci", + "completion", "config", - "set", - "get", - "update", - "outdated", - "prune", - "pack", - "find-dupes", "dedupe", + "deprecate", + "diff", + "dist-tag", + "docs", + "doctor", + "edit", + "exec", + "explain", + "explore", + "find-dupes", + "fund", + "get", + "help", "hook", - "rebuild", + "init", + "install", + "install-ci-test", + "install-test", "link", - "publish", - "star", - "stars", - "unstar", - "adduser", + "ll", "login", "logout", - "unpublish", - "owner", - "access", - "team", - "deprecate", - "shrinkwrap", - "token", - "profile", - "audit", - "fund", - "org", - "help", "ls", - "ll", - "search", - "view", - "init", - "version", - "edit", - "explore", - "docs", - "repo", - "bugs", - "root", - "prefix", - "bin", - "whoami", - "diff", - "dist-tag", + "org", + "outdated", + "owner", + "pack", "ping", "pkg", - "test", - "stop", - "start", + "prefix", + "profile", + "prune", + "publish", + "rebuild", + "repo", "restart", + "root", "run-script", + "search", + "set", "set-script", - "completion", - "doctor", - "exec", - "explain", + "shrinkwrap", + "star", + "stars", + "start", + "stop", + "team", + "test", + "token", + "uninstall", + "unpublish", + "unstar", + "update", + "version", + "view", + "whoami", ], "plumbing": Array [ "birthday", "help-search", ], - "shellouts": Array [ - "exec", - "run-script", - "test", - "start", - "stop", - "restart", - "birthday", - ], - "shorthands": Object { - "c": "config", - "cit": "install-ci-test", - "clean-install": "ci", - "clean-install-test": "cit", - "create": "init", - "ddp": "dedupe", - "i": "install", - "it": "install-test", - "list": "ls", - "ln": "link", - "rb": "rebuild", - "run": "run-script", - "s": "search", - "se": "search", - "t": "test", - "tst": "test", - "un": "uninstall", - "up": "update", - "v": "view", - "why": "explain", - "x": "exec", - }, } ` diff --git a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs index 1f4b0292c0ec6..e6afc973ab10e 100644 --- a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs +++ b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs @@ -514,7 +514,7 @@ All commands: [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] - aliases: i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall, add + aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall Run "npm help install" for more info @@ -826,7 +826,7 @@ All commands: [--no-description] [--searchopts ] [--searchexclude ] [--registry ] [--prefer-online] [--prefer-offline] [--offline] - aliases: s, se, find + aliases: find, s, se Run "npm help search" for more info @@ -944,7 +944,7 @@ All commands: [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] - aliases: un, unlink, remove, rm, r + aliases: unlink, remove, rm, r, un Run "npm help uninstall" for more info @@ -1012,7 +1012,7 @@ All commands: [--json] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] - aliases: v, info, show + aliases: info, show, v Run "npm help view" for more info diff --git a/test/lib/cli.js b/test/lib/cli.js index b6606c69fc429..d36048cd918c6 100644 --- a/test/lib/cli.js +++ b/test/lib/cli.js @@ -14,10 +14,6 @@ const cliMock = async (t, opts) => { const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { ...opts, init: false }) const cli = t.mock('../../lib/cli.js', { '../../lib/npm.js': Npm, - '../../lib/utils/unsupported.js': { - checkForBrokenNode: () => {}, - checkForUnsupportedNode: () => {}, - }, '../../lib/utils/exit-handler.js': exitHandlerMock, ...logMocks, }) @@ -175,3 +171,38 @@ t.test('load error calls error handler', async t => { await cli(process) t.strictSame(exitHandlerCalled(), [err]) }) + +t.test('known broken node version', async t => { + const errors = [] + let exitCode + const { cli } = await cliMock(t, { + globals: { + 'console.error': (msg) => errors.push(msg), + 'process.version': '6.0.0', + 'process.exit': e => exitCode = e, + }, + }) + await cli(process) + t.match(errors, [ + 'ERROR: npm is known not to run on Node.js 6.0.0', + 'You\'ll need to upgrade to a newer Node.js version in order to use this', + 'version of npm. You can find the latest version at https://nodejs.org/', + ]) + t.match(exitCode, 1) +}) + +t.test('unsupported node version', async t => { + const errors = [] + const { cli } = await cliMock(t, { + globals: { + 'console.error': (msg) => errors.push(msg), + 'process.version': '12.6.0', + }, + }) + await cli(process) + t.match(errors, [ + 'npm does not support Node.js 12.6.0', + 'You should probably upgrade to a newer version of node as we', + 'can\'t make any promises that npm will work with this version.', + ]) +}) diff --git a/test/lib/commands/bin.js b/test/lib/commands/bin.js index a889b13361624..46170e765de82 100644 --- a/test/lib/commands/bin.js +++ b/test/lib/commands/bin.js @@ -1,60 +1,32 @@ const t = require('tap') -const { relative, join } = require('path') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const mockGlobals = require('../../fixtures/mock-globals') -const mockBin = async (t, { args = [], config = {} } = {}) => { - const { npm, outputs, ...rest } = await loadMockNpm(t, { - config, - }) - const cmd = await npm.cmd('bin') - await npm.exec('bin', args) - - return { - npm, - cmd, - bin: outputs[0][0], - ...rest, - } -} - -t.test('bin', async t => { - const { cmd, bin, prefix, outputErrors } = await mockBin(t, { - config: { global: false }, - }) - - t.match(cmd.usage, 'bin', 'usage has command name in it') - t.equal(relative(prefix, bin), join('node_modules/.bin'), 'prints the correct directory') - t.strictSame(outputErrors, []) +t.test('bin not global', async t => { + const { npm, joinedOutput, logs } = await loadMockNpm(t) + await npm.exec('bin', []) + t.match(joinedOutput(), npm.localBin) + t.match(logs.error, []) }) -t.test('bin -g', async t => { - mockGlobals(t, { 'process.platform': 'posix' }) - const { globalPrefix, bin, outputErrors } = await mockBin(t, { +t.test('bin global in env.path', async t => { + const { npm, joinedOutput, logs } = await loadMockNpm(t, { config: { global: true }, }) - t.equal(relative(globalPrefix, bin), 'bin', 'prints the correct directory') - t.strictSame(outputErrors, []) -}) - -t.test('bin -g win32', async t => { - mockGlobals(t, { 'process.platform': 'win32' }) - const { globalPrefix, bin, outputErrors } = await mockBin(t, { - config: { global: true }, + mockGlobals(t, { + 'process.env': { path: npm.globalBin }, }) - - t.equal(relative(globalPrefix, bin), '', 'prints the correct directory') - t.strictSame(outputErrors, []) + await npm.exec('bin', []) + t.match(joinedOutput(), npm.globalBin) + t.match(logs.error, []) }) -t.test('bin -g (not in path)', async t => { - const { logs } = await mockBin(t, { +t.test('bin not in path', async t => { + const { npm, joinedOutput, logs } = await loadMockNpm(t, { config: { global: true }, - globals: { - 'process.env.PATH': 'emptypath', - }, }) - - t.strictSame(logs.error[0], ['bin', '(not in PATH env variable)']) + await npm.exec('bin', []) + t.match(joinedOutput(), npm.globalBin) + t.match(logs.error, [['bin', '(not in PATH env variable)']]) }) diff --git a/test/lib/commands/completion.js b/test/lib/commands/completion.js index 045054b74ec7b..d4e6f1199c457 100644 --- a/test/lib/commands/completion.js +++ b/test/lib/commands/completion.js @@ -17,7 +17,7 @@ const loadMockCompletion = async (t, o = {}) => { } const res = await _loadMockNpm(t, { mocks: { - '../../lib/utils/is-windows-shell.js': !!windows, + '../../lib/utils/is-windows.js': { isWindowsShell: !!windows }, ...options.mocks, }, ...options, diff --git a/test/lib/commands/exec.js b/test/lib/commands/exec.js index 3c75c1d8d8273..1f7230d25b654 100644 --- a/test/lib/commands/exec.js +++ b/test/lib/commands/exec.js @@ -72,8 +72,6 @@ const read = (options, cb) => { process.nextTick(() => cb(READ_ERROR, READ_RESULT)) } -const PATH = require('../../../lib/utils/path.js') - let CI_NAME = 'travis-ci' const log = { @@ -154,7 +152,7 @@ t.test('npx foo, bin already exists locally', async t => { stdioString: true, event: 'npx', env: { - PATH: [npm.localBin, ...PATH].join(delimiter), + PATH: [npm.localBin, process.env.PATH].join(delimiter), }, stdio: 'inherit', }, @@ -183,7 +181,7 @@ t.test('npx foo, bin already exists globally', async t => { stdioString: true, event: 'npx', env: { - PATH: [npm.globalBin, ...PATH].join(delimiter), + PATH: [npm.globalBin, process.env.PATH].join(delimiter), }, stdio: 'inherit', }, @@ -1175,7 +1173,7 @@ t.test('workspaces', t => { stdioString: true, event: 'npx', env: { - PATH: [npm.localBin, ...PATH].join(delimiter), + PATH: [npm.localBin, process.env.PATH].join(delimiter), }, stdio: 'inherit', }, diff --git a/test/lib/commands/explore.js b/test/lib/commands/explore.js index d1355d76712a6..5bb211e4503c3 100644 --- a/test/lib/commands/explore.js +++ b/test/lib/commands/explore.js @@ -47,7 +47,6 @@ const output = [] const logs = [] const getExplore = (windows) => { const Explore = t.mock('../../../lib/commands/explore.js', { - '../../../lib/utils/is-windows.js': windows, path: require('path')[windows ? 'win32' : 'posix'], 'read-package-json-fast': mockRPJ, '@npmcli/run-script': mockRunScript, diff --git a/test/lib/commands/run-script.js b/test/lib/commands/run-script.js index 834b61e7474c4..440c8dbad072a 100644 --- a/test/lib/commands/run-script.js +++ b/test/lib/commands/run-script.js @@ -62,7 +62,7 @@ const getRS = windows => { } ), 'proc-log': log, - '../../../lib/utils/is-windows-shell.js': windows, + '../../../lib/utils/is-windows.js': { isWindowsShell: windows }, }) return new RunScript(npm) } @@ -859,7 +859,7 @@ t.test('workspaces', t => { throw new Error('err') }, 'proc-log': log, - '../../../lib/utils/is-windows-shell.js': false, + '../../../lib/utils/is-windows.js': { isWindowsShell: false }, }) const runScript = new RunScript(npm) @@ -877,7 +877,7 @@ t.test('workspaces', t => { RUN_SCRIPTS.push(opts) }, 'proc-log': log, - '../../../lib/utils/is-windows-shell.js': false, + '../../../lib/utils/is-windows.js': { isWindowsShell: false }, }) const runScript = new RunScript(npm) diff --git a/test/lib/load-all-commands.js b/test/lib/load-all-commands.js index ec19575291dc1..34773bba04662 100644 --- a/test/lib/load-all-commands.js +++ b/test/lib/load-all-commands.js @@ -5,11 +5,12 @@ const t = require('tap') const util = require('util') const { load: loadMockNpm } = require('../fixtures/mock-npm.js') -const { cmdList } = require('../../lib/utils/cmd-list.js') +const { cmdList, plumbing } = require('../../lib/utils/cmd-list.js') +const allCmds = [...cmdList, ...plumbing] t.test('load each command', async t => { - t.plan(cmdList.length) - for (const cmd of cmdList.sort((a, b) => a.localeCompare(b, 'en'))) { + t.plan(allCmds.length) + for (const cmd of allCmds.sort((a, b) => a.localeCompare(b, 'en'))) { t.test(cmd, async t => { const { npm, outputs } = await loadMockNpm(t, { config: { usage: true }, diff --git a/test/lib/npm.js b/test/lib/npm.js index 4302437a6f018..998e96314d2b4 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -43,7 +43,6 @@ t.test('not yet loaded', async t => { set: Function, }, version: String, - shelloutCommands: Array, }) t.throws(() => npm.config.set('foo', 'bar')) t.throws(() => npm.config.get('foo')) @@ -549,12 +548,14 @@ t.test('output clears progress and console.logs the message', async t => { t.end() }) -t.test('unknown command', async t => { +t.test('aliases and typos', async t => { const { npm } = await loadMockNpm(t, { load: false }) - await t.rejects( - npm.cmd('thisisnotacommand'), - { code: 'EUNKNOWNCOMMAND' } - ) + await t.rejects(npm.cmd('thisisnotacommand'), { code: 'EUNKNOWNCOMMAND' }) + await t.rejects(npm.cmd(''), { code: 'EUNKNOWNCOMMAND' }) + await t.rejects(npm.cmd('birt'), { code: 'EUNKNOWNCOMMAND' }) + await t.resolves(npm.cmd('it'), { name: 'install-test' }) + await t.resolves(npm.cmd('installTe'), { name: 'install-test' }) + await t.resolves(npm.cmd('birthday'), { name: 'birthday' }) }) t.test('explicit workspace rejection', async t => { diff --git a/test/lib/utils/config/definitions.js b/test/lib/utils/config/definitions.js index a5b34a7499fbe..b387835df55a3 100644 --- a/test/lib/utils/config/definitions.js +++ b/test/lib/utils/config/definitions.js @@ -53,11 +53,11 @@ t.test('editor', t => { t.test('has neither EDITOR nor VISUAL, system specific', t => { mockGlobals(t, { 'process.env': { EDITOR: undefined, VISUAL: undefined } }) const defsWin = t.mock(defpath, { - [isWin]: true, + [isWin]: { isWindows: true }, }) t.equal(defsWin.editor.default, 'notepad.exe') const defsNix = t.mock(defpath, { - [isWin]: false, + [isWin]: { isWindows: false }, }) t.equal(defsNix.editor.default, 'vi') t.end() @@ -69,12 +69,12 @@ t.test('shell', t => { t.test('windows, env.ComSpec then cmd.exe', t => { mockGlobals(t, { 'process.env.ComSpec': 'command.com' }) const defsComSpec = t.mock(defpath, { - [isWin]: true, + [isWin]: { isWindows: true }, }) t.equal(defsComSpec.shell.default, 'command.com') mockGlobals(t, { 'process.env.ComSpec': undefined }) const defsNoComSpec = t.mock(defpath, { - [isWin]: true, + [isWin]: { isWindows: true }, }) t.equal(defsNoComSpec.shell.default, 'cmd') t.end() @@ -83,12 +83,12 @@ t.test('shell', t => { t.test('nix, SHELL then sh', t => { mockGlobals(t, { 'process.env.SHELL': '/usr/local/bin/bash' }) const defsShell = t.mock(defpath, { - [isWin]: false, + [isWin]: { isWindows: false }, }) t.equal(defsShell.shell.default, '/usr/local/bin/bash') mockGlobals(t, { 'process.env.SHELL': undefined }) const defsNoShell = t.mock(defpath, { - [isWin]: false, + [isWin]: { isWindows: false }, }) t.equal(defsNoShell.shell.default, 'sh') t.end() @@ -158,18 +158,18 @@ t.test('unicode allowed?', t => { t.test('cache', t => { mockGlobals(t, { 'process.env.LOCALAPPDATA': 'app/data/local' }) const defsWinLocalAppData = t.mock(defpath, { - [isWin]: true, + [isWin]: { isWindows: true }, }) t.equal(defsWinLocalAppData.cache.default, 'app/data/local/npm-cache') mockGlobals(t, { 'process.env.LOCALAPPDATA': undefined }) const defsWinNoLocalAppData = t.mock(defpath, { - [isWin]: true, + [isWin]: { isWindows: true }, }) t.equal(defsWinNoLocalAppData.cache.default, '~/npm-cache') const defsNix = t.mock(defpath, { - [isWin]: false, + [isWin]: { isWindows: false }, }) t.equal(defsNix.cache.default, '~/.npm') diff --git a/test/lib/utils/deref-command.js b/test/lib/utils/deref-command.js deleted file mode 100644 index 474488c58c254..0000000000000 --- a/test/lib/utils/deref-command.js +++ /dev/null @@ -1,9 +0,0 @@ -const t = require('tap') -const deref = require('../../../lib/utils/deref-command.js') - -t.equal(deref(null), '') -t.equal(deref(8), '') -t.equal(deref('it'), 'install-test') -t.equal(deref('installTe'), 'install-test') -t.equal(deref('birthday'), 'birthday') -t.equal(deref('birt'), '') diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js index 73bbf06fe85e7..23942cca1c078 100644 --- a/test/lib/utils/exit-handler.js +++ b/test/lib/utils/exit-handler.js @@ -32,7 +32,7 @@ t.cleanSnapshot = (path) => cleanDate(cleanCwd(path)) // nerf itself, thinking global.process is broken or gone. mockGlobals(t, { process: Object.assign(new EventEmitter(), { - ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'env'), + ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'env', 'umask'), argv: ['/node', ...process.argv.slice(1)], version: 'v1.0.0', kill: () => {}, @@ -450,7 +450,10 @@ t.test('exits uncleanly when only emitting exit event', async (t) => { t.test('do no fancy handling for shellouts', async t => { const { exitHandler, npm, logs } = await mockExitHandler(t) + const exec = await npm.cmd('exec') + npm.command = 'exec' + npm.commandInstance = exec const loudNoises = () => logs.filter(([level]) => ['warn', 'error'].includes(level)) diff --git a/test/lib/utils/is-windows-bash.js b/test/lib/utils/is-windows-bash.js deleted file mode 100644 index 0fbebdf8e3d53..0000000000000 --- a/test/lib/utils/is-windows-bash.js +++ /dev/null @@ -1,30 +0,0 @@ -const t = require('tap') -const mockGlobal = require('../../fixtures/mock-globals.js') - -const isWindowsBash = () => { - delete require.cache[require.resolve('../../../lib/utils/is-windows-bash.js')] - delete require.cache[require.resolve('../../../lib/utils/is-windows.js')] - return require('../../../lib/utils/is-windows-bash.js') -} - -t.test('posix', (t) => { - mockGlobal(t, { 'process.platform': 'posix' }) - t.equal(isWindowsBash(), false, 'false when not windows') - - t.end() -}) - -t.test('win32', (t) => { - mockGlobal(t, { 'process.platform': 'win32' }) - - mockGlobal(t, { 'process.env': { TERM: 'dumb', MSYSTEM: undefined } }) - t.equal(isWindowsBash(), false, 'false when not mingw or cygwin') - - mockGlobal(t, { 'process.env.TERM': 'cygwin' }) - t.equal(isWindowsBash(), true, 'true when cygwin') - - mockGlobal(t, { 'process.env': { TERM: 'dumb', MSYSTEM: 'MINGW64' } }) - t.equal(isWindowsBash(), true, 'true when mingw') - - t.end() -}) diff --git a/test/lib/utils/is-windows-shell.js b/test/lib/utils/is-windows-shell.js deleted file mode 100644 index 95519925c97ce..0000000000000 --- a/test/lib/utils/is-windows-shell.js +++ /dev/null @@ -1,8 +0,0 @@ -const t = require('tap') -Object.defineProperty(process, 'platform', { - value: 'win32', -}) -const isWindows = require('../../../lib/utils/is-windows.js') -const isWindowsBash = require('../../../lib/utils/is-windows-bash.js') -const isWindowsShell = require('../../../lib/utils/is-windows-shell.js') -t.equal(isWindowsShell, isWindows && !isWindowsBash) diff --git a/test/lib/utils/is-windows.js b/test/lib/utils/is-windows.js index f8f2999c99433..a1d520f0629f6 100644 --- a/test/lib/utils/is-windows.js +++ b/test/lib/utils/is-windows.js @@ -1,8 +1,39 @@ const t = require('tap') -const actuallyWindows = process.platform === 'win32' -t.equal(actuallyWindows, require('../../../lib/utils/is-windows.js')) -Object.defineProperty(process, 'platform', { - value: actuallyWindows ? 'posix' : 'win32', + +const mockGlobals = require('../../fixtures/mock-globals') + +t.test('is not windows', async t => { + mockGlobals(t, { 'process.platform': 'posix' }) + t.match({ + isWindows: false, + isWindowsShell: false, + }, t.mock('../../../lib/utils/is-windows.js')) +}) + +t.test('is windows, shell', async t => { + mockGlobals(t, { + 'process.platform': 'win32', + 'process.env': { + MSYSTEM: 'notmingw', + TERM: 'notcygwin', + }, + }) + t.match({ + isWindows: true, + isWindowsShell: true, + }, t.mock('../../../lib/utils/is-windows.js')) +}) + +t.test('is windows, not shell', async t => { + mockGlobals(t, { + 'process.platform': 'win32', + 'process.env': { + MSYSTEM: 'MINGW32', + TERM: 'cygwin', + }, + }) + t.match({ + isWindows: true, + isWindowsShell: false, + }, t.mock('../../../lib/utils/is-windows.js')) }) -delete require.cache[require.resolve('../../../lib/utils/is-windows.js')] -t.equal(!actuallyWindows, require('../../../lib/utils/is-windows.js')) diff --git a/test/lib/utils/path.js b/test/lib/utils/path.js deleted file mode 100644 index 0a7846d94bc67..0000000000000 --- a/test/lib/utils/path.js +++ /dev/null @@ -1,12 +0,0 @@ -const t = require('tap') -const mod = '../../../lib/utils/path.js' -const delim = require('../../../lib/utils/is-windows.js') ? ';' : ':' -Object.defineProperty(process, 'env', { - value: {}, -}) -process.env.path = ['foo', 'bar', 'baz'].join(delim) -t.strictSame(t.mock(mod), ['foo', 'bar', 'baz']) -process.env.Path = ['a', 'b', 'c'].join(delim) -t.strictSame(t.mock(mod), ['a', 'b', 'c']) -process.env.PATH = ['x', 'y', 'z'].join(delim) -t.strictSame(t.mock(mod), ['x', 'y', 'z']) diff --git a/test/lib/utils/unsupported.js b/test/lib/utils/unsupported.js deleted file mode 100644 index 2703044a227d3..0000000000000 --- a/test/lib/utils/unsupported.js +++ /dev/null @@ -1,102 +0,0 @@ -const t = require('tap') -const unsupported = require('../../../lib/utils/unsupported.js') -const mockGlobals = require('../../fixtures/mock-globals.js') - -const versions = [ - // broken unsupported - ['v0.1.103', true, true], - ['v0.2.0', true, true], - ['v0.3.5', true, true], - ['v0.4.7', true, true], - ['v0.5.3', true, true], - ['v0.6.17', true, true], - ['v0.7.8', true, true], - ['v0.8.28', true, true], - ['v0.9.6', true, true], - ['v0.10.48', true, true], - ['v0.11.16', true, true], - ['v0.12.9', true, true], - ['v1.0.1', true, true], - ['v1.6.0', true, true], - ['v2.3.1', true, true], - ['v3.0.0', true, true], - ['v4.5.0', true, true], - ['v4.8.4', true, true], - ['v5.7.1', true, true], - ['v6.8.1', false, true], - ['v7.0.0-beta23', false, true], - ['v7.2.3', false, true], - ['v8.4.0', false, true], - ['v9.3.0', false, true], - ['v10.0.0-0', false, true], - ['v11.0.0-0', false, true], - ['v12.0.0-0', false, true], - ['v12.13.0-0', false, false], - ['v13.0.0-0', false, true], - ['v14.0.0-0', false, true], - ['v14.15.0-0', false, false], - ['v15.0.0-0', false, true], - ['v16.0.0-0', false, false], -] - -t.test('versions', function (t) { - t.plan(versions.length * 2) - versions.forEach(function (verinfo) { - const version = verinfo[0] - const broken = verinfo[1] - const unsupp = verinfo[2] - const nodejs = unsupported.checkVersion(version) - t.equal(nodejs.broken, broken, version + ' ' + (broken ? '' : 'not ') + 'broken') - t.equal(nodejs.unsupported, unsupp, version + ' ' + (unsupp ? 'unsupported' : 'supported')) - }) - t.end() -}) - -t.test('checkForBrokenNode', t => { - // run it once to not fail - unsupported.checkForBrokenNode() - - const logs = [] - const expectLogs = [ - 'ERROR: npm is known not to run on Node.js 1.2.3', - "You'll need to upgrade to a newer Node.js version in order to use this", - 'version of npm. You can find the latest version at https://nodejs.org/', - ] - - // then make it a thing that fails - mockGlobals(t, { - 'console.error': msg => logs.push(msg), - 'process.version': '1.2.3', - 'process.exit': (code) => { - t.equal(code, 1) - t.strictSame(logs, expectLogs) - t.end() - }, - }) - - unsupported.checkForBrokenNode() -}) - -t.test('checkForUnsupportedNode', t => { - // run it once to not fail or warn - unsupported.checkForUnsupportedNode() - - const logs = [] - const expectLogs = [ - 'npm does not support Node.js 8.0.0', - 'You should probably upgrade to a newer version of node as we', - "can't make any promises that npm will work with this version.", - 'You can find the latest version at https://nodejs.org/', - ] - - // then make it a thing that fails - mockGlobals(t, { - 'console.error': msg => logs.push(msg), - 'process.version': '8.0.0', - }) - - unsupported.checkForUnsupportedNode() - - t.strictSame(logs, expectLogs) - t.end() -})