npx-cli.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #!/usr/bin/env node
  2. const cli = require('../lib/cli.js')
  3. // run the resulting command as `npm exec ...args`
  4. process.argv[1] = require.resolve('./npm-cli.js')
  5. process.argv.splice(2, 0, 'exec')
  6. // TODO: remove the affordances for removed items in npm v9
  7. const removedSwitches = new Set([
  8. 'always-spawn',
  9. 'ignore-existing',
  10. 'shell-auto-fallback',
  11. ])
  12. const removedOpts = new Set([
  13. 'npm',
  14. 'node-arg',
  15. 'n',
  16. ])
  17. const removed = new Set([
  18. ...removedSwitches,
  19. ...removedOpts,
  20. ])
  21. const { definitions, shorthands } = require('@npmcli/config/lib/definitions')
  22. const npmSwitches = Object.entries(definitions)
  23. .filter(([key, { type }]) => type === Boolean ||
  24. (Array.isArray(type) && type.includes(Boolean)))
  25. .map(([key]) => key)
  26. // things that don't take a value
  27. const switches = new Set([
  28. ...removedSwitches,
  29. ...npmSwitches,
  30. 'no-install',
  31. 'quiet',
  32. 'q',
  33. 'version',
  34. 'v',
  35. 'help',
  36. 'h',
  37. ])
  38. // things that do take a value
  39. const opts = new Set([
  40. ...removedOpts,
  41. 'package',
  42. 'p',
  43. 'cache',
  44. 'userconfig',
  45. 'call',
  46. 'c',
  47. 'shell',
  48. 'npm',
  49. 'node-arg',
  50. 'n',
  51. ])
  52. // break out of loop when we find a positional argument or --
  53. // If we find a positional arg, we shove -- in front of it, and
  54. // let the normal npm cli handle the rest.
  55. let i
  56. let sawRemovedFlags = false
  57. for (i = 3; i < process.argv.length; i++) {
  58. const arg = process.argv[i]
  59. if (arg === '--') {
  60. break
  61. } else if (/^-/.test(arg)) {
  62. const [key, ...v] = arg.replace(/^-+/, '').split('=')
  63. switch (key) {
  64. case 'p':
  65. process.argv[i] = ['--package', ...v].join('=')
  66. break
  67. case 'shell':
  68. process.argv[i] = ['--script-shell', ...v].join('=')
  69. break
  70. case 'no-install':
  71. process.argv[i] = '--yes=false'
  72. break
  73. default:
  74. // resolve shorthands and run again
  75. if (shorthands[key] && !removed.has(key)) {
  76. const a = [...shorthands[key]]
  77. if (v.length) {
  78. a.push(v.join('='))
  79. }
  80. process.argv.splice(i, 1, ...a)
  81. i--
  82. continue
  83. }
  84. break
  85. }
  86. if (removed.has(key)) {
  87. // eslint-disable-next-line no-console
  88. console.error(`npx: the --${key} argument has been removed.`)
  89. sawRemovedFlags = true
  90. process.argv.splice(i, 1)
  91. i--
  92. }
  93. if (v.length === 0 && !switches.has(key) &&
  94. (opts.has(key) || !/^-/.test(process.argv[i + 1]))) {
  95. // value will be next argument, skip over it.
  96. if (removed.has(key)) {
  97. // also remove the value for the cut key.
  98. process.argv.splice(i + 1, 1)
  99. } else {
  100. i++
  101. }
  102. }
  103. } else {
  104. // found a positional arg, put -- in front of it, and we're done
  105. process.argv.splice(i, 0, '--')
  106. break
  107. }
  108. }
  109. if (sawRemovedFlags) {
  110. // eslint-disable-next-line no-console
  111. console.error('See `npm help exec` for more information')
  112. }
  113. cli(process)