├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE ├── LICENSE.md ├── Makefile ├── PULL_REQUEST_TEMPLATE ├── README.md ├── appveyor.yml ├── auto-fallback.js ├── bin ├── .gitignore ├── index.js └── package.template.json ├── child.js ├── get-prefix.js ├── index.js ├── locales ├── ca.json ├── cs.json ├── de.json ├── en.json ├── es.json ├── fr.json ├── id.json ├── it.json ├── ja.json ├── ko.json ├── nb.json ├── nl.json ├── nn.json ├── no.json ├── pl.json ├── pt_BR.json ├── ro.json ├── ru.json ├── sr.json ├── tr.json ├── uk.json ├── zh_CN.json └── zh_TW.json ├── package-lock.json ├── package.json ├── parse-args.js ├── test ├── auto-fallback.js ├── child.js ├── get-prefix.js ├── guess-command-name.js ├── index.js ├── parse-args.js ├── util.js └── util │ ├── npx-bin-inherit-stdio.js │ ├── npx-bin.js │ └── test-dir.js ├── util.js └── y.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [zkat] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.nyc_output 3 | /test/cache 4 | libnpx.1 5 | /bin/CHANGELOG.md 6 | /bin/LICENSE.md 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - "10" 5 | - "9" 6 | - "8" 7 | - "6" 8 | cache: 9 | directories: 10 | - $HOME/.npm 11 | before_install: 12 | - npm i -g npm@latest 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | # [10.2.0](https://github.com/zkat/npx/compare/v10.1.1...v10.2.0) (2018-04-13) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **i18n:** fix korean; 쉘 -> 셸 ([#163](https://github.com/zkat/npx/issues/163)) ([11d9fe0](https://github.com/zkat/npx/commit/11d9fe0)) 12 | * **spawn:** spawn child processes with node without relying on the shebang. ([#174](https://github.com/zkat/npx/issues/174)) ([cba97bb](https://github.com/zkat/npx/commit/cba97bb)) 13 | * **windows:** Allow spaces in the node path when using --node-arg ([#173](https://github.com/zkat/npx/issues/173)) ([fe0d48a](https://github.com/zkat/npx/commit/fe0d48a)), closes [#170](https://github.com/zkat/npx/issues/170) 14 | 15 | 16 | ### Features 17 | 18 | * **i18n:** add translation ([#159](https://github.com/zkat/npx/issues/159)) ([5da008b](https://github.com/zkat/npx/commit/5da008b)) 19 | 20 | 21 | 22 | 23 | ## [10.1.1](https://github.com/zkat/npx/compare/v10.1.0...v10.1.1) (2018-04-12) 24 | 25 | 26 | 27 | 28 | # [10.1.0](https://github.com/zkat/npx/compare/v10.0.1...v10.1.0) (2018-04-12) 29 | 30 | 31 | ### Features 32 | 33 | * **spawn:** add --always-spawn to opt out of process takeover optimization feature ([#172](https://github.com/zkat/npx/issues/172)) ([c0d6abc](https://github.com/zkat/npx/commit/c0d6abc)) 34 | 35 | 36 | 37 | 38 | ## [10.0.1](https://github.com/zkat/npx/compare/v10.0.0...v10.0.1) (2018-03-08) 39 | 40 | 41 | ### Bug Fixes 42 | 43 | * **i18n:** Improve French localization ([#158](https://github.com/zkat/npx/issues/158)) ([c88823e](https://github.com/zkat/npx/commit/c88823e)) 44 | * **windows:** on Windows, throw useful error when package contains no binaries([#142](https://github.com/zkat/npx/issues/142)) ([a69276e](https://github.com/zkat/npx/commit/a69276e)), closes [#137](https://github.com/zkat/npx/issues/137) 45 | 46 | 47 | 48 | 49 | # [10.0.0](https://github.com/zkat/npx/compare/v9.7.1...v10.0.0) (2018-03-08) 50 | 51 | 52 | ### Bug Fixes 53 | 54 | * **i18n:** Fix Korean locale ([#130](https://github.com/zkat/npx/issues/130)) ([752db48](https://github.com/zkat/npx/commit/752db48)) 55 | * **index:** remove extraneous logging on Windows ([#136](https://github.com/zkat/npx/issues/136)) ([357e6ab](https://github.com/zkat/npx/commit/357e6ab)), closes [#131](https://github.com/zkat/npx/issues/131) 56 | * **license:** change npx license to ISC ([a617d7b](https://github.com/zkat/npx/commit/a617d7b)) 57 | * **parse-args:** fix version thing for yargs ([30677ed](https://github.com/zkat/npx/commit/30677ed)) 58 | * **prefix:** Handle node_modules without package.json ([#128](https://github.com/zkat/npx/issues/128)) ([f64ae43](https://github.com/zkat/npx/commit/f64ae43)), closes [/github.com/babel/babel/issues/4066#issuecomment-336705199](https://github.com//github.com/babel/babel/issues/4066/issues/issuecomment-336705199) 59 | * **standard:** get things in line with standard 11 ([6cf8e88](https://github.com/zkat/npx/commit/6cf8e88)) 60 | 61 | 62 | ### BREAKING CHANGES 63 | 64 | * **license:** This moves the code over from CC0-1.0 to the ISC license. 65 | 66 | 67 | 68 | 69 | ## [9.7.1](https://github.com/zkat/npx/compare/v9.7.0...v9.7.1) (2017-10-19) 70 | 71 | 72 | ### Bug Fixes 73 | 74 | * **main:** err... oops? ([f24b4e3](https://github.com/zkat/npx/commit/f24b4e3)) 75 | 76 | 77 | 78 | 79 | # [9.7.0](https://github.com/zkat/npx/compare/v9.6.0...v9.7.0) (2017-10-19) 80 | 81 | 82 | ### Bug Fixes 83 | 84 | * **exec:** fixed unix binary pathing issues (#120) ([f80a970](https://github.com/zkat/npx/commit/f80a970)), closes [#120](https://github.com/zkat/npx/issues/120) 85 | 86 | 87 | ### Features 88 | 89 | * **child:** add opts.installerStdio (#126) ([ade03f7](https://github.com/zkat/npx/commit/ade03f7)) 90 | 91 | 92 | 93 | 94 | # [9.6.0](https://github.com/zkat/npx/compare/v9.5.0...v9.6.0) (2017-08-17) 95 | 96 | 97 | ### Features 98 | 99 | * **i18n:** add Arabic translation (#111) ([3c5b99a](https://github.com/zkat/npx/commit/3c5b99a)) 100 | * **i18n:** add Dutch (#108) ([ed116fd](https://github.com/zkat/npx/commit/ed116fd)) 101 | 102 | 103 | 104 | 105 | # [9.5.0](https://github.com/zkat/npx/compare/v9.4.1...v9.5.0) (2017-07-28) 106 | 107 | 108 | ### Features 109 | 110 | * **i18n:** add Polish translations (#99) ([8442f59](https://github.com/zkat/npx/commit/8442f59)) 111 | 112 | 113 | 114 | 115 | ## [9.4.1](https://github.com/zkat/npx/compare/v9.4.0...v9.4.1) (2017-07-21) 116 | 117 | 118 | ### Bug Fixes 119 | 120 | * **i18n:** fix filename for uk.json locale ([2c770e4](https://github.com/zkat/npx/commit/2c770e4)) 121 | 122 | 123 | 124 | 125 | # [9.4.0](https://github.com/zkat/npx/compare/v9.3.2...v9.4.0) (2017-07-21) 126 | 127 | 128 | ### Bug Fixes 129 | 130 | * **i18n:** minor fixes to ru locale (#92) ([f4d5051](https://github.com/zkat/npx/commit/f4d5051)), closes [#92](https://github.com/zkat/npx/issues/92) 131 | 132 | 133 | ### Features 134 | 135 | * **i18n:** `no` locale fallback for Norwegian bokmål ⚠️ In case of weird setups ⚠️ (#91) ([74f0e4c](https://github.com/zkat/npx/commit/74f0e4c)) 136 | * **i18n:** add Bahasa Indonesia locale (#95) ([80dceeb](https://github.com/zkat/npx/commit/80dceeb)) 137 | * **i18n:** add serbian translation (#96) ([040de7a](https://github.com/zkat/npx/commit/040de7a)) 138 | * **i18n:** add Ukrainian locale (#93) ([9a3ef33](https://github.com/zkat/npx/commit/9a3ef33)) 139 | * **i18n:** Added Norwegian (bokmål and nynorsk) translations (#90) ([6c5c733](https://github.com/zkat/npx/commit/6c5c733)) 140 | 141 | 142 | 143 | 144 | ## [9.3.2](https://github.com/zkat/npx/compare/v9.3.1...v9.3.2) (2017-07-17) 145 | 146 | 147 | ### Bug Fixes 148 | 149 | * **exec:** detect a wider range of shebang lines for node scripts (#89) ([1841b6f](https://github.com/zkat/npx/commit/1841b6f)) 150 | * **windows:** escape spawn args because windows is picky (#87) ([314e5eb](https://github.com/zkat/npx/commit/314e5eb)) 151 | * **windows:** get magic shim detection working on Windows (#88) ([255aeeb](https://github.com/zkat/npx/commit/255aeeb)) 152 | 153 | 154 | 155 | 156 | ## [9.3.1](https://github.com/zkat/npx/compare/v9.3.0...v9.3.1) (2017-07-17) 157 | 158 | 159 | ### Bug Fixes 160 | 161 | * **deps:** update to npm[@5](https://github.com/5).3.0 ([2b14de2](https://github.com/zkat/npx/commit/2b14de2)) 162 | 163 | 164 | 165 | 166 | # [9.3.0](https://github.com/zkat/npx/compare/v9.2.3...v9.3.0) (2017-07-17) 167 | 168 | 169 | ### Features 170 | 171 | * **i18n:** add Korean locale (#86) ([3655314](https://github.com/zkat/npx/commit/3655314)) 172 | 173 | 174 | 175 | 176 | ## [9.2.3](https://github.com/zkat/npx/compare/v9.2.2...v9.2.3) (2017-07-17) 177 | 178 | 179 | ### Bug Fixes 180 | 181 | * **paths:** support npm/npx paths with spaces in them ([8f3b829](https://github.com/zkat/npx/commit/8f3b829)) 182 | 183 | 184 | 185 | 186 | ## [9.2.2](https://github.com/zkat/npx/compare/v9.2.1...v9.2.2) (2017-07-15) 187 | 188 | 189 | ### Bug Fixes 190 | 191 | * **npm:** escape path to npm, too ([333d2ff](https://github.com/zkat/npx/commit/333d2ff)) 192 | 193 | 194 | 195 | 196 | ## [9.2.1](https://github.com/zkat/npx/compare/v9.2.0...v9.2.1) (2017-07-14) 197 | 198 | 199 | ### Bug Fixes 200 | 201 | * **windows:** fixed windows binary pathing issues ([761dfe9](https://github.com/zkat/npx/commit/761dfe9)) 202 | 203 | 204 | 205 | 206 | # [9.2.0](https://github.com/zkat/npx/compare/v9.1.0...v9.2.0) (2017-07-14) 207 | 208 | 209 | ### Bug Fixes 210 | 211 | * **binpath:** fix calling binaries from subdirectories ([f185d0d](https://github.com/zkat/npx/commit/f185d0d)) 212 | * **i18n:** Fix typos in french locale (#78) ([f277fc7](https://github.com/zkat/npx/commit/f277fc7)), closes [#78](https://github.com/zkat/npx/issues/78) 213 | 214 | 215 | ### Features 216 | 217 | * **i18n:** Add German translations (#79) ([c81e26d](https://github.com/zkat/npx/commit/c81e26d)) 218 | * **i18n:** add zh_TW translation (#80) ([98288d8](https://github.com/zkat/npx/commit/98288d8)) 219 | 220 | 221 | 222 | 223 | # [9.1.0](https://github.com/zkat/npx/compare/v9.0.7...v9.1.0) (2017-07-12) 224 | 225 | 226 | ### Bug Fixes 227 | 228 | * **call:** only npm run env if package.json exists ([370f395](https://github.com/zkat/npx/commit/370f395)) 229 | * **i18n:** Fix grammar and spelling for de.json (#63) ([b14020f](https://github.com/zkat/npx/commit/b14020f)), closes [#63](https://github.com/zkat/npx/issues/63) 230 | * **i18n:** wording revisions for Brazilian Portuguese (#75) ([b5dc536](https://github.com/zkat/npx/commit/b5dc536)) 231 | * **npm:** path directly to the npm-cli.js script ([d531206](https://github.com/zkat/npx/commit/d531206)) 232 | * **rimraf:** fix rimraf.sync is not a function issue ([d2ecba3](https://github.com/zkat/npx/commit/d2ecba3)) 233 | * **windows:** get npx working well on Windows again (#69) ([6cfb8de](https://github.com/zkat/npx/commit/6cfb8de)), closes [#60](https://github.com/zkat/npx/issues/60) [#58](https://github.com/zkat/npx/issues/58) [#62](https://github.com/zkat/npx/issues/62) 234 | 235 | 236 | ### Features 237 | 238 | * **i18n:** add Czech translation (#76) ([8a0b3f6](https://github.com/zkat/npx/commit/8a0b3f6)) 239 | * **i18n:** Add Turkish translation (#73) ([26e5edf](https://github.com/zkat/npx/commit/26e5edf)) 240 | * **i18n:** Added support for Italian language (#71) ([6883e75](https://github.com/zkat/npx/commit/6883e75)) 241 | * **i18n:** Fix Romanian translation (#70) ([fd6bbcf](https://github.com/zkat/npx/commit/fd6bbcf)), closes [#70](https://github.com/zkat/npx/issues/70) 242 | * **node:** add --node-arg support to pass flags to node for script binaries (#77) ([65665bd](https://github.com/zkat/npx/commit/65665bd)) 243 | 244 | 245 | 246 | 247 | ## [9.0.7](https://github.com/zkat/npx/compare/v9.0.6...v9.0.7) (2017-07-11) 248 | 249 | 250 | ### Bug Fixes 251 | 252 | * **i18n:** Fix some Catalan translations (#59) ([11c8a19](https://github.com/zkat/npx/commit/11c8a19)), closes [#59](https://github.com/zkat/npx/issues/59) 253 | 254 | 255 | 256 | 257 | ## [9.0.6](https://github.com/zkat/npx/compare/v9.0.5...v9.0.6) (2017-07-11) 258 | 259 | 260 | ### Bug Fixes 261 | 262 | * **auto-fallback:** fix syntax error in bash/zsh auto-fallback ([d8b19db](https://github.com/zkat/npx/commit/d8b19db)) 263 | 264 | 265 | 266 | 267 | ## [9.0.5](https://github.com/zkat/npx/compare/v9.0.4...v9.0.5) (2017-07-11) 268 | 269 | 270 | ### Bug Fixes 271 | 272 | * **npx:** something went wrong with the 9.0.4 build and bundledeps ([75fc436](https://github.com/zkat/npx/commit/75fc436)) 273 | 274 | 275 | 276 | 277 | ## [9.0.4](https://github.com/zkat/npx/compare/v9.0.3...v9.0.4) (2017-07-11) 278 | 279 | 280 | ### Bug Fixes 281 | 282 | * **auto-fallback:** prevent infinite loop if npx disappears ([6c24e58](https://github.com/zkat/npx/commit/6c24e58)) 283 | * **bin:** add repository and more detailed author info ([906574e](https://github.com/zkat/npx/commit/906574e)) 284 | * **bin:** pin the npx bin's dependencies ([ae62f7a](https://github.com/zkat/npx/commit/ae62f7a)) 285 | * **build:** make sure changelog and license are copied to bin ([4fbb599](https://github.com/zkat/npx/commit/4fbb599)) 286 | * **deps:** stop bundling deps in libnpx itself ([c3e56e9](https://github.com/zkat/npx/commit/c3e56e9)) 287 | * **errors:** print command not found for packages without valid binaries ([9b24359](https://github.com/zkat/npx/commit/9b24359)) 288 | * **help:** --no-install help text was contradicting itself ([9d96f5e](https://github.com/zkat/npx/commit/9d96f5e)) 289 | * **install:** prevent concurrent npx runs from clobbering each other ([6b35c91](https://github.com/zkat/npx/commit/6b35c91)) 290 | * **npx:** npx npx npx npx npx npx npx npx npx works again ([875d4cd](https://github.com/zkat/npx/commit/875d4cd)) 291 | * **updater:** dependency injection for update-notifier target ([c3027a9](https://github.com/zkat/npx/commit/c3027a9)) 292 | * **updater:** ignore some kinds of update-notifier errors ([7631bbe](https://github.com/zkat/npx/commit/7631bbe)) 293 | 294 | 295 | 296 | 297 | ## [9.0.3](https://github.com/zkat/npx/compare/v9.0.2...v9.0.3) (2017-07-08) 298 | 299 | 300 | ### Bug Fixes 301 | 302 | * **version:** hand version to yargs directly ([e0b5eeb](https://github.com/zkat/npx/commit/e0b5eeb)) 303 | 304 | 305 | 306 | 307 | ## [9.0.2](https://github.com/zkat/npx/compare/v9.0.1...v9.0.2) (2017-07-08) 308 | 309 | 310 | ### Bug Fixes 311 | 312 | * **manpage:** fix manpage for real because files syntax is weird ([9145e2a](https://github.com/zkat/npx/commit/9145e2a)) 313 | 314 | 315 | 316 | 317 | ## [9.0.1](https://github.com/zkat/npx/compare/v9.0.0...v9.0.1) (2017-07-08) 318 | 319 | 320 | ### Bug Fixes 321 | 322 | * **man:** make sure manpage is used in npx bin ([704b94f](https://github.com/zkat/npx/commit/704b94f)) 323 | 324 | 325 | 326 | 327 | # [9.0.0](https://github.com/zkat/npx/compare/v8.1.1...v9.0.0) (2017-07-08) 328 | 329 | 330 | ### Features 331 | 332 | * **libnpx:** libify main npx codebase ([643f58e](https://github.com/zkat/npx/commit/643f58e)) 333 | * **npx:** create a new binary for standalone publishing ([da5a3b7](https://github.com/zkat/npx/commit/da5a3b7)) 334 | 335 | 336 | ### BREAKING CHANGES 337 | 338 | * **libnpx:** This version of npx can no longer be used as a 339 | standalone binary. It will be available on the registry as `libnpx`, 340 | and a separate project will take over the role of the main `npx` binary. 341 | 342 | 343 | 344 | 345 | ## [8.1.1](https://github.com/zkat/npx/compare/v8.1.0...v8.1.1) (2017-07-06) 346 | 347 | 348 | ### Bug Fixes 349 | 350 | * **deps:** bump all deps ([6ea24bf](https://github.com/zkat/npx/commit/6ea24bf)) 351 | * **npm:** bump npm to 5.1.0 for a bunch of fixes ([18e4587](https://github.com/zkat/npx/commit/18e4587)) 352 | 353 | 354 | 355 | 356 | # [8.1.0](https://github.com/zkat/npx/compare/v8.0.1...v8.1.0) (2017-06-27) 357 | 358 | 359 | ### Bug Fixes 360 | 361 | * **i18n:** minor tweaks to ja.json (#46) ([1ed63c2](https://github.com/zkat/npx/commit/1ed63c2)) 362 | 363 | 364 | ### Features 365 | 366 | * **i18n:** Update pt_BR.json (#51) ([d292f22](https://github.com/zkat/npx/commit/d292f22)) 367 | 368 | 369 | 370 | 371 | ## [8.0.1](https://github.com/zkat/npx/compare/v8.0.0...v8.0.1) (2017-06-27) 372 | 373 | 374 | ### Bug Fixes 375 | 376 | * **npm:** bump npm version for more bugfixes ([30711a8](https://github.com/zkat/npx/commit/30711a8)) 377 | * **npm:** Use --parseable option to work around output quirks ([8cb75a2](https://github.com/zkat/npx/commit/8cb75a2)) 378 | 379 | 380 | 381 | 382 | # [8.0.0](https://github.com/zkat/npx/compare/v7.0.0...v8.0.0) (2017-06-24) 383 | 384 | 385 | ### Features 386 | 387 | * **exec:** auto-guess binaries when different from pkg name ([139c434](https://github.com/zkat/npx/commit/139c434)) 388 | 389 | 390 | ### BREAKING CHANGES 391 | 392 | * **exec:** `npx ember-cli` and such things will now execute the 393 | binary based on some guesswork, but only when using the shorthand format 394 | for npx execution, with no `-p` option or `-c`. This might cause npx to 395 | unintentionally execute the wrong binary if the package in question has 396 | multiple non-matching binaries, but that should be rare. 397 | 398 | 399 | 400 | 401 | # [7.0.0](https://github.com/zkat/npx/compare/v6.2.0...v7.0.0) (2017-06-24) 402 | 403 | 404 | ### Bug Fixes 405 | 406 | * **win32:** improve win32 situation a bit (#50) ([b7ad934](https://github.com/zkat/npx/commit/b7ad934)) 407 | 408 | 409 | ### Features 410 | 411 | * **local:** improve the behavior when calling ./local paths (#48) ([2e418d1](https://github.com/zkat/npx/commit/2e418d1)) 412 | 413 | 414 | ### BREAKING CHANGES 415 | 416 | * **local:** `npx ./something` will now execute `./something` as a 417 | binary or script instead of trying to install it as npm would. Other behavior 418 | related to local path deps has likewise been changed. See 419 | [#49](https://github.com/zkat/npx/issues/49) for a detailed explanation 420 | of all the various cases and how each of them is handled. 421 | 422 | 423 | 424 | 425 | # [6.2.0](https://github.com/zkat/npx/compare/v6.1.0...v6.2.0) (2017-06-23) 426 | 427 | 428 | ### Bug Fixes 429 | 430 | * **child:** iron out a few crinkles and add tests ([b3b5ef6](https://github.com/zkat/npx/commit/b3b5ef6)) 431 | * **execCmd:** only reuse the current process if no shell passed in ([e413cff](https://github.com/zkat/npx/commit/e413cff)) 432 | * **execCmd:** use the module built-in directly ([6f741c2](https://github.com/zkat/npx/commit/6f741c2)) 433 | * **help:** fuck it. just hard-code it ([d5d5085](https://github.com/zkat/npx/commit/d5d5085)) 434 | * **main:** only exec if this is the main module ([9631e2a](https://github.com/zkat/npx/commit/9631e2a)) 435 | 436 | 437 | ### Features 438 | 439 | * **i18n:** Update fr.json (#44) ([ea47c4f](https://github.com/zkat/npx/commit/ea47c4f)) 440 | * **i18n:** update the Romanian translation. (#42) ([2ed36b6](https://github.com/zkat/npx/commit/2ed36b6)) 441 | 442 | 443 | 444 | 445 | # [6.1.0](https://github.com/zkat/npx/compare/v6.0.0...v6.1.0) (2017-06-21) 446 | 447 | 448 | ### Bug Fixes 449 | 450 | * **deps:** remove unused gauge dep ([aa40a34](https://github.com/zkat/npx/commit/aa40a34)) 451 | 452 | 453 | ### Features 454 | 455 | * **i18n:** update ru locale (#41) ([7c84dee](https://github.com/zkat/npx/commit/7c84dee)) 456 | * **i18n:** update zh_CN (#40) ([da4ec67](https://github.com/zkat/npx/commit/da4ec67)) 457 | * **perf:** run node-based commands in the current process ([6efcde4](https://github.com/zkat/npx/commit/6efcde4)) 458 | 459 | 460 | 461 | 462 | # [6.0.0](https://github.com/zkat/npx/compare/v5.4.0...v6.0.0) (2017-06-20) 463 | 464 | 465 | ### Bug Fixes 466 | 467 | * **call:** stop parsing -c for commands + fix corner cases ([bd4e538](https://github.com/zkat/npx/commit/bd4e538)) 468 | * **child:** exec does not have the information needed to correctly escape its args ([6714992](https://github.com/zkat/npx/commit/6714992)) 469 | * **guessCmdName:** tests failed because of lazy npa ([53a0119](https://github.com/zkat/npx/commit/53a0119)) 470 | * **i18n:** gender inclusiveness fix for french version (#37) ([04920ae](https://github.com/zkat/npx/commit/04920ae)), closes [#37](https://github.com/zkat/npx/issues/37) 471 | * **i18n:** typo 😇 (#38) ([ede4a53](https://github.com/zkat/npx/commit/ede4a53)) 472 | * **install:** handle JSON parsing failures ([bec2887](https://github.com/zkat/npx/commit/bec2887)) 473 | * **output:** stop printing out Command Failed messages ([873cffe](https://github.com/zkat/npx/commit/873cffe)) 474 | * **parseArgs:** fix booboo in fast path ([d1e5487](https://github.com/zkat/npx/commit/d1e5487)) 475 | * **perf:** fast-path `npx foo` arg parsing ([ba4fe71](https://github.com/zkat/npx/commit/ba4fe71)) 476 | * **perf:** remove bluebird and defer some requires for SPEED ([00fc313](https://github.com/zkat/npx/commit/00fc313)) 477 | 478 | 479 | ### Features 480 | 481 | * **i18n:** add Romanian translations. (#34) ([9e98bd0](https://github.com/zkat/npx/commit/9e98bd0)) 482 | * **i18n:** added a few more localizable strings ([779d950](https://github.com/zkat/npx/commit/779d950)) 483 | * **i18n:** updated ca.json ([af7a035](https://github.com/zkat/npx/commit/af7a035)) 484 | * **i18n:** updated es.json ([414644f](https://github.com/zkat/npx/commit/414644f)) 485 | * **i18n:** updated ja.json ([448b082](https://github.com/zkat/npx/commit/448b082)) 486 | * **i18n:** Ze German Translation (#35) ([6f003f5](https://github.com/zkat/npx/commit/6f003f5)) 487 | * **package:** report number of temp packages installed ([5b7fe8d](https://github.com/zkat/npx/commit/5b7fe8d)) 488 | * **perf:** only launch update-notifier when npx installs stuff ([549d413](https://github.com/zkat/npx/commit/549d413)) 489 | * **quiet:** added -q/--quiet to suppress output from npx itself ([16607d9](https://github.com/zkat/npx/commit/16607d9)) 490 | 491 | 492 | ### BREAKING CHANGES 493 | 494 | * **call:** `npx -c "foo"` will no longer install `foo`. Use `-p` to specicify packages to install. npx will no longer assume any particular format or escape status for `-c` strings: they will be passed directly, unparsed, and unaltered, to child_process.spawn. 495 | 496 | 497 | 498 | 499 | # [5.4.0](https://github.com/zkat/npx/compare/v5.3.0...v5.4.0) (2017-06-17) 500 | 501 | 502 | ### Bug Fixes 503 | 504 | * **i18n:** some corrections for es.json ([4d50b71](https://github.com/zkat/npx/commit/4d50b71)) 505 | * **i18n:** update locale files with bugfixes ([77caf82](https://github.com/zkat/npx/commit/77caf82)) 506 | * **i18n:** Y utility was ignoring falsy entries ([f22a4d0](https://github.com/zkat/npx/commit/f22a4d0)) 507 | * **i18n:** してください -> します ([01671af](https://github.com/zkat/npx/commit/01671af)) 508 | 509 | 510 | ### Features 511 | 512 | * **i18n:** add catalan translation ([579efa1](https://github.com/zkat/npx/commit/579efa1)) 513 | * **i18n:** add pt-br translation (#33) ([6142551](https://github.com/zkat/npx/commit/6142551)) 514 | * **i18n:** added largely machine-translated ja.json ([827705f](https://github.com/zkat/npx/commit/827705f)) 515 | * **i18n:** adds russian translation (#32) ([b2619c1](https://github.com/zkat/npx/commit/b2619c1)) 516 | 517 | 518 | 519 | 520 | # [5.3.0](https://github.com/zkat/npx/compare/v5.2.0...v5.3.0) (2017-06-13) 521 | 522 | 523 | ### Features 524 | 525 | * **i18n:** add Chinese translation (#31) ([24e1b31](https://github.com/zkat/npx/commit/24e1b31)) 526 | 527 | 528 | 529 | 530 | # [5.2.0](https://github.com/zkat/npx/compare/v5.1.3...v5.2.0) (2017-06-12) 531 | 532 | 533 | ### Bug Fixes 534 | 535 | * **i18n:** removing extra spacing in fr.json ([002e2b8](https://github.com/zkat/npx/commit/002e2b8)) 536 | 537 | 538 | ### Features 539 | 540 | * **i18n:** add french locale (#29) ([662395b](https://github.com/zkat/npx/commit/662395b)) 541 | 542 | 543 | 544 | 545 | ## [5.1.3](https://github.com/zkat/npx/compare/v5.1.2...v5.1.3) (2017-06-12) 546 | 547 | 548 | ### Bug Fixes 549 | 550 | * **fallback:** put the Y in the wrong place lol ([d6bf8aa](https://github.com/zkat/npx/commit/d6bf8aa)) 551 | 552 | 553 | 554 | 555 | ## [5.1.2](https://github.com/zkat/npx/compare/v5.1.1...v5.1.2) (2017-06-10) 556 | 557 | 558 | 559 | 560 | ## [5.1.1](https://github.com/zkat/npx/compare/v5.1.0...v5.1.1) (2017-06-10) 561 | 562 | 563 | ### Bug Fixes 564 | 565 | * **i18n:** forgot to add locales to files ([4118d6a](https://github.com/zkat/npx/commit/4118d6a)) 566 | 567 | 568 | 569 | 570 | # [5.1.0](https://github.com/zkat/npx/compare/v5.0.3...v5.1.0) (2017-06-10) 571 | 572 | 573 | ### Bug Fixes 574 | 575 | * **exit:** let process exit normally to finish writes ([c50a398](https://github.com/zkat/npx/commit/c50a398)) 576 | 577 | 578 | ### Features 579 | 580 | * **i18n:** added es.json ([6cf58b9](https://github.com/zkat/npx/commit/6cf58b9)) 581 | * **i18n:** set up i18n plus baseline en.json locale ([b67bb3a](https://github.com/zkat/npx/commit/b67bb3a)) 582 | 583 | 584 | 585 | 586 | ## [5.0.3](https://github.com/zkat/npx/compare/v5.0.2...v5.0.3) (2017-06-09) 587 | 588 | 589 | ### Bug Fixes 590 | 591 | * **fallback:** exec is no ([42c1d30](https://github.com/zkat/npx/commit/42c1d30)) 592 | 593 | 594 | 595 | 596 | ## [5.0.2](https://github.com/zkat/npx/compare/v5.0.1...v5.0.2) (2017-06-09) 597 | 598 | 599 | ### Bug Fixes 600 | 601 | * **fallback:** allow fallback to local anyway ([569cf2c](https://github.com/zkat/npx/commit/569cf2c)) 602 | 603 | 604 | 605 | 606 | ## [5.0.1](https://github.com/zkat/npx/compare/v5.0.0...v5.0.1) (2017-06-09) 607 | 608 | 609 | 610 | 611 | # [5.0.0](https://github.com/zkat/npx/compare/v4.0.3...v5.0.0) (2017-06-09) 612 | 613 | 614 | ### Features 615 | 616 | * **fallback:** by default, only fall back if you have an @ in the name ([bea08a0](https://github.com/zkat/npx/commit/bea08a0)) 617 | 618 | 619 | ### BREAKING CHANGES 620 | 621 | * **fallback:** auto-fallback will no longer fall back unless there was 622 | an @ sign in the command. 623 | 624 | 625 | 626 | 627 | ## [4.0.3](https://github.com/zkat/npx/compare/v4.0.2...v4.0.3) (2017-06-04) 628 | 629 | 630 | ### Bug Fixes 631 | 632 | * **npm:** use --userconfig when querying for npm cache config (#28) ([21bc3bf](https://github.com/zkat/npx/commit/21bc3bf)) 633 | 634 | 635 | 636 | 637 | ## [4.0.2](https://github.com/zkat/npx/compare/v4.0.1...v4.0.2) (2017-06-04) 638 | 639 | 640 | ### Bug Fixes 641 | 642 | * **install:** get windows workin (#27) ([9472175](https://github.com/zkat/npx/commit/9472175)) 643 | 644 | 645 | 646 | 647 | ## [4.0.1](https://github.com/zkat/npx/compare/v4.0.0...v4.0.1) (2017-06-04) 648 | 649 | 650 | ### Bug Fixes 651 | 652 | * **cmd:** make sure to use our own, enriched path ([9c89c2a](https://github.com/zkat/npx/commit/9c89c2a)) 653 | * **error:** join args with a space on Command failed error ([c2f6f18](https://github.com/zkat/npx/commit/c2f6f18)) 654 | 655 | 656 | 657 | 658 | # [4.0.0](https://github.com/zkat/npx/compare/v3.0.0...v4.0.0) (2017-06-03) 659 | 660 | 661 | ### Features 662 | 663 | * **call:** -c now loads same env as run-script ([76ae44c](https://github.com/zkat/npx/commit/76ae44c)) 664 | * **npm:** allow configuration of npm binary ([e5d5634](https://github.com/zkat/npx/commit/e5d5634)) 665 | * **npm:** embed npm binary ([a2cae9d](https://github.com/zkat/npx/commit/a2cae9d)) 666 | 667 | 668 | ### BREAKING CHANGES 669 | 670 | * **call:** scripts invoked with -c will now have a bunch of 671 | variables added to them that were not there before. 672 | * **npm:** npx will no longer use the system npm -- it embeds its own 673 | 674 | 675 | 676 | 677 | # [3.0.0](https://github.com/zkat/npx/compare/v2.1.0...v3.0.0) (2017-06-03) 678 | 679 | 680 | ### Bug Fixes 681 | 682 | * **args:** accept argv as arg and fix minor bugs ([46f10fe](https://github.com/zkat/npx/commit/46f10fe)) 683 | * **deps:** explicitly add mkdirp and rimraf to devDeps ([832c75d](https://github.com/zkat/npx/commit/832c75d)) 684 | * **docs:** misc tweaks to docs ([ed70a7b](https://github.com/zkat/npx/commit/ed70a7b)) 685 | * **exec:** escape binaries and args to cp.exec (#18) ([55d6a11](https://github.com/zkat/npx/commit/55d6a11)) 686 | * **fallback:** shells were sometimes ignored based on $SHELL ([07b7efc](https://github.com/zkat/npx/commit/07b7efc)) 687 | * **get-prefix:** nudge isRootPath ([1ab31eb](https://github.com/zkat/npx/commit/1ab31eb)) 688 | * **help:** correctly enable -h and --help ([adc2f45](https://github.com/zkat/npx/commit/adc2f45)) 689 | * **startup:** delay loading some things to speed up startup ([6b32bf5](https://github.com/zkat/npx/commit/6b32bf5)) 690 | 691 | 692 | ### Features 693 | 694 | * **cmd:** do some heuristic guesswork on default command names (#23) ([2404420](https://github.com/zkat/npx/commit/2404420)) 695 | * **ignore:** add --ignore-existing option (#20) ([0866a83](https://github.com/zkat/npx/commit/0866a83)) 696 | * **install:** added --no-install option to prevent install fallbacks ([a5fbdaf](https://github.com/zkat/npx/commit/a5fbdaf)) 697 | * **package:** multiple --package options are now accepted ([f2fa6b3](https://github.com/zkat/npx/commit/f2fa6b3)) 698 | * **save:** remove all save-related functionality (#19) ([ab77f6c](https://github.com/zkat/npx/commit/ab77f6c)) 699 | * **shell:** run -c strings inside a system shell (#22) ([17db461](https://github.com/zkat/npx/commit/17db461)) 700 | 701 | 702 | ### BREAKING CHANGES 703 | 704 | * **save:** npx can no longer be used to save packages locally or globally. Use an actual package manager for that, instead. 705 | 706 | 707 | 708 | 709 | # [2.1.0](https://github.com/zkat/npx/compare/v2.0.1...v2.1.0) (2017-06-01) 710 | 711 | 712 | ### Features 713 | 714 | * **opts:** add --shell-auto-fallback (#7) ([ac9cb40](https://github.com/zkat/npx/commit/ac9cb40)) 715 | 716 | 717 | 718 | 719 | ## [2.0.1](https://github.com/zkat/npx/compare/v2.0.0...v2.0.1) (2017-05-31) 720 | 721 | 722 | ### Bug Fixes 723 | 724 | * **exec:** use command lookup joined with current PATH ([d9175e8](https://github.com/zkat/npx/commit/d9175e8)) 725 | 726 | 727 | 728 | 729 | # [2.0.0](https://github.com/zkat/npx/compare/v1.1.1...v2.0.0) (2017-05-31) 730 | 731 | 732 | ### Bug Fixes 733 | 734 | * **npm:** manually look up npm path for Windows compat ([0fe8fbf](https://github.com/zkat/npx/commit/0fe8fbf)) 735 | 736 | 737 | ### Features 738 | 739 | * **commands:** -p and [@version](https://github.com/version) now trigger installs ([9668c83](https://github.com/zkat/npx/commit/9668c83)) 740 | 741 | 742 | ### BREAKING CHANGES 743 | 744 | * **commands:** If a command has an explicit --package option, or if the command has an @version part, any version of the command in $PATH will be ignored and a regular install will be executed. 745 | 746 | 747 | 748 | 749 | ## [1.1.1](https://github.com/zkat/npx/compare/v1.1.0...v1.1.1) (2017-05-30) 750 | 751 | 752 | ### Bug Fixes 753 | 754 | * **docs:** make sure man page gets installed ([2aadc16](https://github.com/zkat/npx/commit/2aadc16)) 755 | 756 | 757 | 758 | 759 | # [1.1.0](https://github.com/zkat/npx/compare/v1.0.2...v1.1.0) (2017-05-30) 760 | 761 | 762 | ### Bug Fixes 763 | 764 | * **help:** update usage string for help ([0747cff](https://github.com/zkat/npx/commit/0747cff)) 765 | * **main:** exit if no package was parsed ([cdb579d](https://github.com/zkat/npx/commit/cdb579d)) 766 | * **opts:** allow -- to prevent further parsing ([db7a0e4](https://github.com/zkat/npx/commit/db7a0e4)) 767 | 768 | 769 | ### Features 770 | 771 | * **updates:** added update-notifier ([8dc91d4](https://github.com/zkat/npx/commit/8dc91d4)) 772 | 773 | 774 | 775 | 776 | ## [1.0.2](https://github.com/zkat/npx/compare/v1.0.1...v1.0.2) (2017-05-30) 777 | 778 | 779 | ### Bug Fixes 780 | 781 | * **pkg:** bundle deps to guarantee global install precision ([3e21217](https://github.com/zkat/npx/commit/3e21217)) 782 | 783 | 784 | 785 | 786 | ## [1.0.1](https://github.com/zkat/npx/compare/v1.0.0...v1.0.1) (2017-05-30) 787 | 788 | 789 | ### Bug Fixes 790 | 791 | * **build:** add dummy test file to let things build ([6199eb6](https://github.com/zkat/npx/commit/6199eb6)) 792 | * **docs:** fix arg documentation in readme/manpage ([d1cf44c](https://github.com/zkat/npx/commit/d1cf44c)) 793 | * **opts:** add --version/-v ([2633a0e](https://github.com/zkat/npx/commit/2633a0e)) 794 | 795 | 796 | 797 | 798 | # 1.0.0 (2017-05-30) 799 | 800 | 801 | ### Features 802 | 803 | * **npx:** initial working implementation ([a83a67d](https://github.com/zkat/npx/commit/a83a67d)) 804 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## When Something Happens 4 | 5 | If you see a Code of Conduct violation, follow these steps: 6 | 7 | 1. Let the person know that what they did is not appropriate and ask them to stop and/or edit their message(s) or commits. 8 | 2. That person should immediately stop the behavior and correct the issue. 9 | 3. If this doesn’t happen, or if you're uncomfortable speaking up, [contact the maintainers](#contacting-maintainers). 10 | 4. As soon as available, a maintainer will look into the issue, and take [further action (see below)](#further-enforcement), starting with a warning, then temporary block, then long-term repo or organization ban. 11 | 12 | When reporting, please include any relevant details, links, screenshots, context, or other information that may be used to better understand and resolve the situation. 13 | 14 | **The maintainer team will prioritize the well-being and comfort of the recipients of the violation over the comfort of the violator.** See [some examples below](#enforcement-examples). 15 | 16 | ## Our Pledge 17 | 18 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers of this project pledge to making participation in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, technical preferences, nationality, personal appearance, race, religion, or sexual identity and orientation. 19 | 20 | ## Our Standards 21 | 22 | Examples of behavior that contributes to creating a positive environment include: 23 | 24 | * Using welcoming and inclusive language. 25 | * Being respectful of differing viewpoints and experiences. 26 | * Gracefully accepting constructive feedback. 27 | * Focusing on what is best for the community. 28 | * Showing empathy and kindness towards other community members. 29 | * Encouraging and raising up your peers in the project so you can all bask in hacks and glory. 30 | 31 | Examples of unacceptable behavior by participants include: 32 | 33 | * The use of sexualized language or imagery and unwelcome sexual attention or advances, including when simulated online. The only exception to sexual topics is channels/spaces specifically for topics of sexual identity. 34 | * Casual mention of slavery or indentured servitude and/or false comparisons of one's occupation or situation to slavery. Please consider using or asking about alternate terminology when referring to such metaphors in technology. 35 | * Making light of/making mocking comments about trigger warnings and content warnings. 36 | * Trolling, insulting/derogatory comments, and personal or political attacks. 37 | * Public or private harassment, deliberate intimidation, or threats. 38 | * Publishing others' private information, such as a physical or electronic address, without explicit permission. This includes any sort of "outing" of any aspect of someone's identity without their consent. 39 | * Publishing private screenshots or quotes of interactions in the context of this project without all quoted users' *explicit* consent. 40 | * Publishing of private communication that doesn't have to do with reporting harrassment. 41 | * Any of the above even when [presented as "ironic" or "joking"](https://en.wikipedia.org/wiki/Hipster_racism). 42 | * Any attempt to present "reverse-ism" versions of the above as violations. Examples of reverse-isms are "reverse racism", "reverse sexism", "heterophobia", and "cisphobia". 43 | * Unsolicited explanations under the assumption that someone doesn't already know it. Ask before you teach! Don't assume what people's knowledge gaps are. 44 | * [Feigning or exaggerating surprise](https://www.recurse.com/manual#no-feigned-surprise) when someone admits to not knowing something. 45 | * "[Well-actuallies](https://www.recurse.com/manual#no-well-actuallys)" 46 | * Other conduct which could reasonably be considered inappropriate in a professional or community setting. 47 | 48 | ## Scope 49 | 50 | This Code of Conduct applies both within spaces involving this project and in other spaces involving community members. This includes the repository, its Pull Requests and Issue tracker, its Twitter community, private email communications in the context of the project, and any events where members of the project are participating, as well as adjacent communities and venues affecting the project's members. 51 | 52 | Depending on the violation, the maintainers may decide that violations of this code of conduct that have happened outside of the scope of the community may deem an individual unwelcome, and take appropriate action to maintain the comfort and safety of its members. 53 | 54 | ### Other Community Standards 55 | 56 | As a project on GitHub, this project is additionally covered by the [GitHub Community Guidelines](https://help.github.com/articles/github-community-guidelines/). 57 | 58 | Additionally, as a project hosted on npm, is is covered by [npm, Inc's Code of Conduct](https://www.npmjs.com/policies/conduct). 59 | 60 | Enforcement of those guidelines after violations overlapping with the above are the responsibility of the entities, and enforcement may happen in any or all of the services/communities. 61 | 62 | ## Maintainer Enforcement Process 63 | 64 | Once the maintainers get involved, they will follow a documented series of steps and do their best to preserve the well-being of project members. This section covers actual concrete steps. 65 | 66 | ### Contacting Maintainers 67 | 68 | You may get in touch with the maintainer team through any of the following methods: 69 | 70 | * Through email: 71 | * [kzm@sykosomatic.org](mailto:kzm@sykosomatic.org) (Kat Marchán) 72 | 73 | * Through Twitter: 74 | * [@maybekatz](https://twitter.com/maybekatz) (Kat Marchán) 75 | 76 | ### Further Enforcement 77 | 78 | If you've already followed the [initial enforcement steps](#enforcement), these are the steps maintainers will take for further enforcement, as needed: 79 | 80 | 1. Repeat the request to stop. 81 | 2. If the person doubles down, they will have offending messages removed or edited by a maintainers given an official warning. The PR or Issue may be locked. 82 | 3. If the behavior continues or is repeated later, the person will be blocked from participating for 24 hours. 83 | 4. If the behavior continues or is repeated after the temporary block, a long-term (6-12mo) ban will be used. 84 | 85 | On top of this, maintainers may remove any offending messages, images, contributions, etc, as they deem necessary. 86 | 87 | Maintainers reserve full rights to skip any of these steps, at their discretion, if the violation is considered to be a serious and/or immediate threat to the health and well-being of members of the community. These include any threats, serious physical or verbal attacks, and other such behavior that would be completely unacceptable in any social setting that puts our members at risk. 88 | 89 | Members expelled from events or venues with any sort of paid attendance will not be refunded. 90 | 91 | ### Who Watches the Watchers? 92 | 93 | Maintainers and other leaders who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. These may include anything from removal from the maintainer team to a permanent ban from the community. 94 | 95 | Additionally, as a project hosted on both GitHub and npm, [their own Codes of Conducts may be applied against maintainers of this project](#other-community-standards), externally of this project's procedures. 96 | 97 | ### Enforcement Examples 98 | 99 | #### The Best Case 100 | 101 | The vast majority of situations work out like this. This interaction is common, and generally positive. 102 | 103 | > Alex: "Yeah I used X and it was really crazy!" 104 | 105 | > Patt (not a maintainer): "Hey, could you not use that word? What about 'ridiculous' instead?" 106 | 107 | > Alex: "oh sorry, sure." -> edits old comment to say "it was really confusing!" 108 | 109 | #### The Maintainer Case 110 | 111 | Sometimes, though, you need to get maintainers involved. Maintainers will do their best to resolve conflicts, but people who were harmed by something **will take priority**. 112 | 113 | > Patt: "Honestly, sometimes I just really hate using $library and anyone who uses it probably sucks at their job." 114 | 115 | > Alex: "Whoa there, could you dial it back a bit? There's a CoC thing about attacking folks' tech use like that." 116 | 117 | > Patt: "I'm not attacking anyone, what's your problem?" 118 | 119 | > Alex: "@maintainers hey uh. Can someone look at this issue? Patt is getting a bit aggro. I tried to nudge them about it, but nope." 120 | 121 | > KeeperOfCommitBits: (on issue) "Hey Patt, maintainer here. Could you tone it down? This sort of attack is really not okay in this space." 122 | 123 | > Patt: "Leave me alone I haven't said anything bad wtf is wrong with you." 124 | 125 | > KeeperOfCommitBits: (deletes user's comment), "@patt I mean it. Please refer to the CoC over at (URL to this CoC) if you have questions, but you can consider this an actual warning. I'd appreciate it if you reworded your messages in this thread, since they made folks there uncomfortable. Let's try and be kind, yeah?" 126 | 127 | > Patt: "@keeperofbits Okay sorry. I'm just frustrated and I'm kinda burnt out and I guess I got carried away. I'll DM Alex a note apologizing and edit my messages. Sorry for the trouble." 128 | 129 | > KeeperOfCommitBits: "@patt Thanks for that. I hear you on the stress. Burnout sucks :/. Have a good one!" 130 | 131 | #### The Nope Case 132 | 133 | > PepeTheFrog🐸: "Hi, I am a literal actual nazi and I think white supremacists are quite fashionable." 134 | 135 | > Patt: "NOOOOPE. OH NOPE NOPE." 136 | 137 | > Alex: "JFC NO. NOPE. @keeperofbits NOPE NOPE LOOK HERE" 138 | 139 | > KeeperOfCommitBits: "👀 Nope. NOPE NOPE NOPE. 🔥" 140 | 141 | > PepeTheFrog🐸 has been banned from all organization or user repositories belonging to KeeperOfCommitBits. 142 | 143 | ## Attribution 144 | 145 | This Code of Conduct was generated using [WeAllJS Code of Conduct Generator](https://npm.im/weallbehave), which is based on the [WeAllJS Code of 146 | Conduct](https://wealljs.org/code-of-conduct), which is itself based on 147 | [Contributor Covenant](http://contributor-covenant.org), version 1.4, available 148 | at 149 | [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4), 150 | and the LGBTQ in Technology Slack [Code of 151 | Conduct](http://lgbtq.technology/coc.html). 152 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## How do I... 4 | 5 | * [Use This Guide](#introduction)? 6 | * Ask or Say Something? 🤔🐛😱 7 | * [Request Support](#request-support) 8 | * [Report an Error or Bug](#report-an-error-or-bug) 9 | * [Request a Feature](#request-a-feature) 10 | * Make Something? 🤓👩🏽‍💻📜🍳 11 | * [Project Setup](#project-setup) 12 | * [Contribute Documentation](#contribute-documentation) 13 | * [Contribute Code](#contribute-code) 14 | * Manage Something ✅🙆🏼💃👔 15 | * [Provide Support on Issues](#provide-support-on-issues) 16 | * [Label Issues](#label-issues) 17 | * [Clean Up Issues and PRs](#clean-up-issues-and-prs) 18 | * [Review Pull Requests](#review-pull-requests) 19 | * [Merge Pull Requests](#merge-pull-requests) 20 | * [Tag a Release](#tag-a-release) 21 | * [Join the Project Team](#join-the-project-team) 22 | * Add a Guide Like This One [To My Project](#attribution)? 🤖😻👻 23 | 24 | ## Introduction 25 | 26 | Thank you so much for your interest in contributing!. All types of contributions are encouraged and valued. See the [table of contents](#toc) for different ways to help and details about how this project handles them!📝 27 | 28 | Please make sure to read the relevant section before making your contribution! It will make it a lot easier for us maintainers to make the most of it and smooth out the experience for all involved. 💚 29 | 30 | The [Project Team](#join-the-project-team) looks forward to your contributions. 🙌🏾✨ 31 | 32 | ## Request Support 33 | 34 | If you have a question about this project, how to use it, or just need clarification about something: 35 | 36 | * Open an Issue at https://github.com/zkat/npx/issues 37 | * Provide as much context as you can about what you're running into. 38 | * Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. If not, please be ready to provide that information if maintainers ask for it. 39 | 40 | Once it's filed: 41 | 42 | * The project team will [label the issue](#label-issues). 43 | * Someone will try to have a response soon. 44 | * If you or the maintainers don't respond to an issue for 30 days, the [issue will be closed](#clean-up-issues-and-prs). If you want to come back to it, reply (once, please), and we'll reopen the existing issue. Please avoid filing new issues as extensions of one you already made. 45 | 46 | ## Report an Error or Bug 47 | 48 | If you run into an error or bug with the project: 49 | 50 | * Open an Issue at https://github.com/zkat/npx/issues 51 | * Include *reproduction steps* that someone else can follow to recreate the bug or error on their own. 52 | * Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant. If not, please be ready to provide that information if maintainers ask for it. 53 | 54 | Once it's filed: 55 | 56 | * The project team will [label the issue](#label-issues). 57 | * A team member will try to reproduce the issue with your provided steps. If there are no repro steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced. 58 | * If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#contribute-code). 59 | * If you or the maintainers don't respond to an issue for 30 days, the [issue will be closed](#clean-up-issues-and-prs). If you want to come back to it, reply (once, please), and we'll reopen the existing issue. Please avoid filing new issues as extensions of one you already made. 60 | * `critical` issues may be left open, depending on perceived immediacy and severity, even past the 30 day deadline. 61 | 62 | ## Request a Feature 63 | 64 | If the project doesn't do something you need or want it to do: 65 | 66 | * Open an Issue at https://github.com/zkat/npx/issues 67 | * Provide as much context as you can about what you're running into. 68 | * Please try and be clear about why existing features and alternatives would not work for you. 69 | 70 | Once it's filed: 71 | 72 | * The project team will [label the issue](#label-issues). 73 | * The project team will evaluate the feature request, possibly asking you more questions to understand its purpose and any relevant requirements. If the issue is closed, the team will convey their reasoning and suggest an alternative path forward. 74 | * If the feature request is accepted, it will be marked for implementation with `feature-accepted`, which can then be done by either by a core team member or by anyone in the community who wants to [contribute code](#contribute-code). 75 | 76 | Note: The team is unlikely to be able to accept every single feature request that is filed. Please understand if they need to say no. 77 | 78 | ## Project Setup 79 | 80 | So you wanna contribute some code! That's great! This project uses GitHub Pull Requests to manage contributions, so [read up on how to fork a GitHub project and file a PR](https://guides.github.com/activities/forking) if you've never done it before. 81 | 82 | If this seems like a lot or you aren't able to do all this setup, you might also be able to [edit the files directly](https://help.github.com/articles/editing-files-in-another-user-s-repository/) without having to do any of this setup. Yes, [even code](#contribute-code). 83 | 84 | If you want to go the usual route and run the project locally, though: 85 | 86 | * [Install Node.js](https://nodejs.org/en/download/) 87 | * [Fork the project](https://guides.github.com/activities/forking/#fork) 88 | 89 | Then in your terminal: 90 | * `cd path/to/your/clone` 91 | * `npm install` 92 | * `npm test` 93 | 94 | And you should be ready to go! 95 | 96 | ## Contribute Documentation 97 | 98 | Documentation is a super important, critical part of this project. Docs are how we keep track of what we're doing, how, and why. It's how we stay on the same page about our policies. And it's how we tell others everything they need in order to be able to use this project -- or contribute to it. So thank you in advance. 99 | 100 | Documentation contributions of any size are welcome! Feel free to file a PR even if you're just rewording a sentence to be more clear, or fixing a spelling mistake! 101 | 102 | To contribute documentation: 103 | 104 | * [Set up the project](#project-setup). 105 | * Edit or add any relevant documentation. 106 | * Make sure your changes are formatted correctly and consistently with the rest of the documentation. 107 | * Re-read what you wrote, and run a spellchecker on it to make sure you didn't miss anything. 108 | * In your commit message(s), begin the first line with `docs: `. For example: `docs: Adding a doc contrib section to CONTRIBUTING.md`. 109 | * Write clear, concise commit message(s) using [conventional-changelog format](https://github.com/conventional-changelog/conventional-changelog-angular/blob/master/convention.md). Documentation commits should use `docs(): `. 110 | * Go to https://github.com/zkat/npx/pulls and open a new pull request with your changes. 111 | * If your PR is connected to an open issue, add a line in your PR's description that says `Fixes: #123`, where `#123` is the number of the issue you're fixing. 112 | 113 | Once you've filed the PR: 114 | 115 | * One or more maintainers will use GitHub's review feature to review your PR. 116 | * If the maintainer asks for any changes, edit your changes, push, and ask for another review. 117 | * If the maintainer decides to pass on your PR, they will thank you for the contribution and explain why they won't be accepting the changes. That's ok! We still really appreciate you taking the time to do it, and we don't take that lightly. 💚 118 | * If your PR gets accepted, it will be marked as such, and merged into the `latest` branch soon after. Your contribution will be distributed to the masses next time the maintainers [tag a release](#tag-a-release) 119 | 120 | ## Contribute Code 121 | 122 | We like code commits a lot! They're super handy, and they keep the project going and doing the work it needs to do to be useful to others. 123 | 124 | Code contributions of just about any size are acceptable! 125 | 126 | The main difference between code contributions and documentation contributions is that contributing code requires inclusion of relevant tests for the code being added or changed. Contributions without accompanying tests will be held off until a test is added, unless the maintainers consider the specific tests to be either impossible, or way too much of a burden for such a contribution. 127 | 128 | To contribute code: 129 | 130 | * [Set up the project](#project-setup). 131 | * Make any necessary changes to the source code. 132 | * Include any [additional documentation](#contribute-documentation) the changes might need. 133 | * Write tests that verify that your contribution works as expected. 134 | * Write clear, concise commit message(s) using [conventional-changelog format](https://github.com/conventional-changelog/conventional-changelog-angular/blob/master/convention.md). 135 | * Dependency updates, additions, or removals must be in individual commits, and the message must use the format: `(deps): PKG@VERSION`, where `` is any of the usual `conventional-changelog` prefixes, at your discretion. 136 | * Go to https://github.com/zkat/npx/pulls and open a new pull request with your changes. 137 | * If your PR is connected to an open issue, add a line in your PR's description that says `Fixes: #123`, where `#123` is the number of the issue you're fixing. 138 | 139 | Once you've filed the PR: 140 | 141 | * Barring special circumstances, maintainers will not review PRs until all checks pass (Travis, AppVeyor, etc). 142 | * One or more maintainers will use GitHub's review feature to review your PR. 143 | * If the maintainer asks for any changes, edit your changes, push, and ask for another review. Additional tags (such as `needs-tests`) will be added depending on the review. 144 | * If the maintainer decides to pass on your PR, they will thank you for the contribution and explain why they won't be accepting the changes. That's ok! We still really appreciate you taking the time to do it, and we don't take that lightly. 💚 145 | * If your PR gets accepted, it will be marked as such, and merged into the `latest` branch soon after. Your contribution will be distributed to the masses next time the maintainers [tag a release](#tag-a-release) 146 | 147 | ## Provide Support on Issues 148 | 149 | [Needs Collaborator](#join-the-project-team): none 150 | 151 | Helping out other users with their questions is a really awesome way of contributing to any community. It's not uncommon for most of the issues on an open source projects being support-related questions by users trying to understand something they ran into, or find their way around a known bug. 152 | 153 | Sometimes, the `support` label will be added to things that turn out to actually be other things, like bugs or feature requests. In that case, suss out the details with the person who filed the original issue, add a comment explaining what the bug is, and change the label from `support` to `bug` or `feature`. If you can't do this yourself, @mention a maintainer so they can do it. 154 | 155 | In order to help other folks out with their questions: 156 | 157 | * Go to the issue tracker and [filter open issues by the `support` label](https://github.com/zkat/npx/issues?q=is%3Aopen+is%3Aissue+label%3Asupport). 158 | * Read through the list until you find something that you're familiar enough with to give an answer to. 159 | * Respond to the issue with whatever details are needed to clarify the question, or get more details about what's going on. 160 | * Once the discussion wraps up and things are clarified, either close the issue, or ask the original issue filer (or a maintainer) to close it for you. 161 | 162 | Some notes on picking up support issues: 163 | 164 | * Avoid responding to issues you don't know you can answer accurately. 165 | * As much as possible, try to refer to past issues with accepted answers. Link to them from your replies with the `#123` format. 166 | * Be kind and patient with users -- often, folks who have run into confusing things might be upset or impatient. This is ok. Try to understand where they're coming from, and if you're too uncomfortable with the tone, feel free to stay away or withdraw from the issue. (note: if the user is outright hostile or is violating the CoC, [refer to the Code of Conduct](CODE_OF_CONDUCT.md) to resolve the conflict). 167 | 168 | ## Label Issues 169 | 170 | [Needs Collaborator](#join-the-project-team): Issue Tracker 171 | 172 | One of the most important tasks in handling issues is labeling them usefully and accurately. All other tasks involving issues ultimately rely on the issue being classified in such a way that relevant parties looking to do their own tasks can find them quickly and easily. 173 | 174 | In order to label issues, [open up the list of unlabeled issues](https://github.com/zkat/npx/issues?q=is%3Aopen+is%3Aissue+no%3Alabel) and, **from newest to oldest**, read through each one and apply issue labels according to the table below. If you're unsure about what label to apply, skip the issue and try the next one: don't feel obligated to label each and every issue yourself! 175 | 176 | Label | Apply When | Notes 177 | --- | --- | --- 178 | `bug` | Cases where the code (or documentation) is behaving in a way it wasn't intended to. | If something is happening that surprises the *user* but does not go against the way the code is designed, it should use the `enhancement` label. 179 | `critical` | Added to `bug` issues if the problem described makes the code completely unusable in a common situation. | 180 | `documentation` | Added to issues or pull requests that affect any of the documentation for the project. | Can be combined with other labels, such as `bug` or `enhancement`. 181 | `duplicate` | Added to issues or PRs that refer to the exact same issue as another one that's been previously labeled. | Duplicate issues should be marked and closed right away, with a message referencing the issue it's a duplicate of (with `#123`) 182 | `enhancement` | Added to [feature requests](#request-a-feature), PRs, or documentation issues that are purely additive: the code or docs currently work as expected, but a change is being requested or suggested. | 183 | `help wanted` | Applied by [Committers](#join-the-project-team) to issues and PRs that they would like to get outside help for. Generally, this means it's lower priority for the maintainer team to itself implement, but that the community is encouraged to pick up if they so desire | Never applied on first-pass labeling. 184 | `in-progress` | Applied by [Committers](#join-the-project-team) to PRs that are pending some work before they're ready for review. | The original PR submitter should @mention the team member that applied the label once the PR is complete. 185 | `performance` | This issue or PR is directly related to improving performance. | 186 | `refactor` | Added to issues or PRs that deal with cleaning up or modifying the project for the betterment of it. | 187 | `starter` | Applied by [Committers](#join-the-project-team) to issues that they consider good introductions to the project for people who have not contributed before. These are not necessarily "easy", but rather focused around how much context is necessary in order to understand what needs to be done for this project in particular. | Existing project members are expected to stay away from these unless they increase in priority. 188 | `support` | This issue is either asking a question about how to use the project, clarifying the reason for unexpected behavior, or possibly reporting a `bug` but does not have enough detail yet to determine whether it would count as such. | The label should be switched to `bug` if reliable reproduction steps are provided. Issues primarily with unintended configurations of a user's environment are not considered bugs, even if they cause crashes. 189 | `tests` | This issue or PR either requests or adds primarily tests to the project. | If a PR is pending tests, that will be handled through the [PR review process](#review-pull-requests) 190 | `wontfix` | Labelers may apply this label to issues that clearly have nothing at all to do with the project or are otherwise entirely outside of its scope/sphere of influence. [Committers](#join-the-project-team) may apply this label and close an issue or PR if they decide to pass on an otherwise relevant issue. | The issue or PR should be closed as soon as the label is applied, and a clear explanation provided of why the label was used. Contributors are free to contest the labeling, but the decision ultimately falls on committers as to whether to accept something or not. 191 | 192 | ## Clean Up Issues and PRs 193 | 194 | [Needs Collaborator](#join-the-project-team): Issue Tracker 195 | 196 | Issues and PRs can go stale after a while. Maybe they're abandoned. Maybe the team will just plain not have time to address them any time soon. 197 | 198 | In these cases, they should be closed until they're brought up again or the interaction starts over. 199 | 200 | To clean up issues and PRs: 201 | 202 | * Search the issue tracker for issues or PRs, and add the term `updated:<=YYYY-MM-DD`, where the date is 30 days before today. 203 | * Go through each issue *from oldest to newest*, and close them if **all of the following are true**: 204 | * not opened by a maintainer 205 | * not marked as `critical` 206 | * not marked as `starter` or `help wanted` (these might stick around for a while, in general, as they're intended to be available) 207 | * no explicit messages in the comments asking for it to be left open 208 | * does not belong to a milestone 209 | * Leave a message when closing saying "Cleaning up stale issue. Please reopen or ping us if and when you're ready to resume this. See https://github.com/zkat/npx/blob/latest/CONTRIBUTING.md#clean-up-issues-and-prs for more details." 210 | 211 | ## Review Pull Requests 212 | 213 | [Needs Collaborator](#join-the-project-team): Issue Tracker 214 | 215 | While anyone can comment on a PR, add feedback, etc, PRs are only *approved* by team members with Issue Tracker or higher permissions. 216 | 217 | PR reviews use [GitHub's own review feature](https://help.github.com/articles/about-pull-request-reviews/), which manages comments, approval, and review iteration. 218 | 219 | Some notes: 220 | 221 | * You may ask for minor changes ("nitpicks"), but consider whether they are really blockers to merging: try to err on the side of "approve, with comments". 222 | * *ALL PULL REQUESTS* should be covered by a test: either by a previously-failing test, an existing test that covers the entire functionality of the submitted code, or new tests to verify any new/changed behavior. All tests must also pass and follow established conventions. Test coverage should not drop, unless the specific case is considered reasonable by maintainers. 223 | * Please make sure you're familiar with the code or documentation being updated, unless it's a minor change (spellchecking, minor formatting, etc). You may @mention another project member who you think is better suited for the review, but still provide a non-approving review of your own. 224 | * Be extra kind: people who submit code/doc contributions are putting themselves in a pretty vulnerable position, and have put time and care into what they've done (even if that's not obvious to you!) -- always respond with respect, be understanding, but don't feel like you need to sacrifice your standards for their sake, either. Just don't be a jerk about it? 225 | 226 | ## Merge Pull Requests 227 | 228 | [Needs Collaborator](#join-the-project-team): Committer 229 | 230 | TBD - need to hash out a bit more of this process. 231 | 232 | ## Tag A Release 233 | 234 | [Needs Collaborator](#join-the-project-team): Committer 235 | 236 | TBD - need to hash out a bit more of this process. The most important bit here is probably that all tests must pass, and tags must use [semver](https://semver.org). 237 | 238 | ## Join the Project Team 239 | 240 | ### Ways to Join 241 | 242 | There are many ways to contribute! Most of them don't require any official status unless otherwise noted. That said, there's a couple of positions that grant special repository abilities, and this section describes how they're granted and what they do. 243 | 244 | All of the below positions are granted based on the project team's needs, as well as their consensus opinion about whether they would like to work with the person and think that they would fit well into that position. The process is relatively informal, and it's likely that people who express interest in participating can just be granted the permissions they'd like. 245 | 246 | You can spot a collaborator on the repo by looking for the `[Collaborator]` or `[Owner]` tags next to their names. 247 | 248 | Permission | Description 249 | --- | --- 250 | Issue Tracker | Granted to contributors who express a strong interest in spending time on the project's issue tracker. These tasks are mainly [labeling issues](#label-issues), [cleaning up old ones](#clean-up-issues-and-prs), and [reviewing pull requests](#review-pull-requests), as well as all the usual things non-team-member contributors can do. Issue handlers should not merge pull requests, tag releases, or directly commit code themselves: that should still be done through the usual pull request process. Becoming an Issue Handler means the project team trusts you to understand enough of the team's process and context to implement it on the issue tracker. 251 | Committer | Granted to contributors who want to handle the actual pull request merges, tagging new versions, etc. Committers should have a good level of familiarity with the codebase, and enough context to understand the implications of various changes, as well as a good sense of the will and expectations of the project team. 252 | Admin/Owner | Granted to people ultimately responsible for the project, its community, etc. 253 | 254 | ## Attribution 255 | 256 | This guide was generated using the WeAllJS `CONTRIBUTING.md` generator. [Make your own](https://npm.im/weallcontribute)! 257 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) npm, Inc. 4 | 5 | Permission to use, copy, modify, and/or distribute this software for 6 | any purpose with or without fee is hereby granted, provided that the 7 | above copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS 10 | ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 | COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 13 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 14 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 16 | USE OR PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | text-files = README.md CHANGELOG.md LICENSE.md 2 | 3 | bin: bin/npx.1 bin/package.json bin/node_modules $(text-files) 4 | 5 | bin/%: $(text-files) 6 | cp $(text-files) bin/ 7 | 8 | bin/npx.1: libnpx.1 9 | cat $< | sed s/libnpx/npx/ > $@ 10 | 11 | libnpx.1: README.md 12 | npm run docs 13 | 14 | bin/package.json: package.json bin/package.template.json 15 | cat bin/package.template.json | npx json -e "this.version = '$$(cat package.json | npx json version)'" > $@ 16 | npx json -I -f $@ -e "this.dependencies.libnpx = '$$(cat $@ | npx json version)'" 17 | 18 | bin/node_modules: bin/package.json 19 | cd bin && npm i 20 | 21 | clean: 22 | rm -rf bin/npx.1 bin/package.json bin/node_modules libnpx.1 $(addprefix bin/, $(text-files)) 23 | 24 | .PHONY: clean 25 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm](https://img.shields.io/npm/v/npx.svg)](https://npm.im/npx) [![license](https://img.shields.io/npm/l/npx.svg)](https://npm.im/npx) [![Travis](https://img.shields.io/travis/zkat/npx.svg)](https://travis-ci.org/zkat/npx) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/zkat/npx?svg=true)](https://ci.appveyor.com/project/zkat/npx) [![Coverage Status](https://coveralls.io/repos/github/zkat/npx/badge.svg?branch=latest)](https://coveralls.io/github/zkat/npx?branch=latest) 2 | 3 | # npx(1) -- execute npm package binaries 4 | 5 | ## NOTE: This repo has moved to https://github.com/npm/npx. 6 | 7 | ## SYNOPSIS 8 | 9 | `npx [options] [@version] [command-arg]...` 10 | 11 | `npx [options] [-p|--package ]... [command-arg]...` 12 | 13 | `npx [options] -c ''` 14 | 15 | `npx --shell-auto-fallback [shell]` 16 | 17 | ## INSTALL 18 | 19 | `npm install -g npx` 20 | 21 | ## DESCRIPTION 22 | 23 | Executes `` either from a local `node_modules/.bin`, or from a central cache, installing any packages needed in order for `` to run. 24 | 25 | By default, `npx` will check whether `` exists in `$PATH`, or in the local project binaries, and execute that. If `` is not found, it will be installed prior to execution. 26 | 27 | Unless a `--package` option is specified, `npx` will try to guess the name of the binary to invoke depending on the specifier provided. All package specifiers understood by `npm` may be used with `npx`, including git specifiers, remote tarballs, local directories, or scoped packages. 28 | 29 | If a full specifier is included, or if `--package` is used, npx will always use a freshly-installed, temporary version of the package. This can also be forced with the `--ignore-existing` flag. 30 | 31 | * `-p, --package ` - define the package to be installed. This defaults to the value of ``. This is only needed for packages with multiple binaries if you want to call one of the other executables, or where the binary name does not match the package name. If this option is provided `` will be executed as-is, without interpreting `@version` if it's there. Multiple `--package` options may be provided, and all the packages specified will be installed. 32 | 33 | * `--no-install` - If passed to `npx`, it will only try to run `` if it already exists in the current path or in `$prefix/node_modules/.bin`. It won't try to install missing commands. 34 | 35 | * `--cache ` - set the location of the npm cache. Defaults to npm's own cache settings. 36 | 37 | * `--userconfig ` - path to the user configuration file to pass to npm. Defaults to whatever npm's current default is. 38 | 39 | * `-c ` - Execute `` inside an `npm run-script`-like shell environment, with all the usual environment variables available. Only the first item in `` will be automatically used as ``. Any others _must_ use `-p`. 40 | 41 | * `--shell ` - The shell to invoke the command with, if any. 42 | 43 | * `--shell-auto-fallback []` - Generates shell code to override your shell's "command not found" handler with one that calls `npx`. Tries to figure out your shell, or you can pass its name (either `bash`, `fish`, or `zsh`) as an option. See below for how to install. 44 | 45 | * `--ignore-existing` - If this flag is set, npx will not look in `$PATH`, or in the current package's `node_modules/.bin` for an existing version before deciding whether to install. Binaries in those paths will still be available for execution, but will be shadowed by any packages requested by this install. 46 | 47 | * `-q, --quiet` - Suppressed any output from npx itself (progress bars, error messages, install reports). Subcommand output itself will not be silenced. 48 | 49 | * `-n, --node-arg` - Extra node argument to supply to node when binary is a node script. You can supply this option multiple times to add more arguments. 50 | 51 | * `-v, --version` - Show the current npx version. 52 | 53 | ## EXAMPLES 54 | 55 | ### Running a project-local bin 56 | 57 | ``` 58 | $ npm i -D webpack 59 | $ npx webpack ... 60 | ``` 61 | 62 | ### One-off invocation without local installation 63 | 64 | ``` 65 | $ npm rm webpack 66 | $ npx webpack -- ... 67 | $ cat package.json 68 | ...webpack not in "devDependencies"... 69 | ``` 70 | 71 | ### Invoking a command from a github repository 72 | 73 | ``` 74 | $ npx github:piuccio/cowsay 75 | ...or... 76 | $ npx git+ssh://my.hosted.git:cowsay.git#semver:^1 77 | ...etc... 78 | ``` 79 | 80 | ### Execute a full shell command using one npx call w/ multiple packages 81 | 82 | ``` 83 | $ npx -p lolcatjs -p cowsay -c \ 84 | 'echo "$npm_package_name@$npm_package_version" | cowsay | lolcatjs' 85 | ... 86 | _____ 87 | < your-cool-package@1.2.3 > 88 | ----- 89 | \ ^__^ 90 | \ (oo)\_______ 91 | (__)\ )\/\ 92 | ||----w | 93 | || || 94 | ``` 95 | 96 | ### Run node binary with --inspect 97 | 98 | ``` 99 | $ npx --node-arg=--inspect cowsay 100 | Debugger listening on ws://127.0.0.1:9229/.... 101 | ``` 102 | 103 | ### Specify a node version to run npm scripts (or anything else!) 104 | 105 | ``` 106 | npx -p node@8 npm run build 107 | ``` 108 | 109 | ## SHELL AUTO FALLBACK 110 | 111 | You can configure `npx` to run as your default fallback command when you type something in the command line with an `@` but the command is not found. This includes installing packages that were not found in the local prefix either. 112 | 113 | For example: 114 | 115 | ``` 116 | $ npm@4 --version 117 | (stderr) npm@4 not found. Trying with npx... 118 | 4.6.1 119 | $ asdfasdfasf 120 | zsh: command not found: asfdasdfasdf 121 | ``` 122 | 123 | Currently, `zsh`, `bash` (>= 4), and `fish` are supported. You can access these completion scripts using `npx --shell-auto-fallback `. 124 | 125 | To install permanently, add the relevant line below to your `~/.bashrc`, `~/.zshrc`, `~/.config/fish/config.fish`, or as needed. To install just for the shell session, simply run the line. 126 | 127 | You can optionally pass through `--no-install` when generating the fallback to prevent it from installing packages if the command is missing. 128 | 129 | ### For bash@>=4: 130 | 131 | ``` 132 | $ source <(npx --shell-auto-fallback bash) 133 | ``` 134 | 135 | ### For zsh: 136 | 137 | ``` 138 | $ source <(npx --shell-auto-fallback zsh) 139 | ``` 140 | 141 | ### For fish: 142 | 143 | ``` 144 | $ source (npx --shell-auto-fallback fish | psub) 145 | ``` 146 | 147 | ## ACKNOWLEDGEMENTS 148 | 149 | Huge thanks to [Kwyn Meagher](https://blog.kwyn.io) for generously donating the package name in the main npm registry. Previously `npx` was used for a Tessel board Neopixels library, which can now be found under [`npx-tessel`](https://npm.im/npx-tessel). 150 | 151 | ## AUTHOR 152 | 153 | Written by [Kat Marchan](https://github.com/zkat). 154 | 155 | ## REPORTING BUGS 156 | 157 | Please file any relevant issues [on Github.](https://github.com/zkat/npx) 158 | 159 | ## LICENSE 160 | 161 | This work is released by its authors into the public domain under CC0-1.0. See `LICENSE.md` for details. 162 | 163 | ## SEE ALSO 164 | 165 | * `npm(1)` 166 | * `npm-run-script(1)` 167 | * `npm-config(7)` 168 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: "10" 4 | - nodejs_version: "9" 5 | - nodejs_version: "8" 6 | - nodejs_version: "6" 7 | 8 | platform: 9 | - x64 10 | 11 | install: 12 | - ps: Install-Product node $env:nodejs_version $env:platform 13 | - npm config set spin false 14 | - npm i -g npm@latest 15 | - npm install 16 | 17 | cache: 18 | - '%APPDATA%\npm-cache' 19 | 20 | test_script: 21 | - npm test 22 | 23 | matrix: 24 | fast_finish: true 25 | 26 | build: off 27 | -------------------------------------------------------------------------------- /auto-fallback.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Y = require('./y.js') 4 | 5 | function mkPosix (opts) { 6 | return ` 7 | command_not_found_${opts.isBash ? 'handle' : 'handler'}() { 8 | # Do not run within a pipe 9 | if test ! -t 1; then 10 | >&2 echo "${Y`command not found: ${'$1'}`}" 11 | return 127 12 | fi 13 | if which npx > /dev/null; then 14 | echo "${Y`${'$1'} not found. Trying with npx...`}" >&2 15 | else 16 | return 127 17 | fi 18 | if ! [[ $1 =~ @ ]]; then 19 | npx --no-install "$@" 20 | else 21 | npx "$@" 22 | fi 23 | return $? 24 | }` 25 | } 26 | 27 | function mkFish (opts) { 28 | return ` 29 | function __fish_command_not_found_on_interactive --on-event fish_prompt 30 | functions --erase __fish_command_not_found_handler 31 | functions --erase __fish_command_not_found_setup 32 | 33 | function __fish_command_not_found_handler --on-event fish_command_not_found 34 | if which npx > /dev/null 35 | echo "${Y`${'$argv[1]'} not found. Trying with npx...`}" >&2 36 | else 37 | return 127 38 | end 39 | if string match -q -r @ $argv[1] 40 | npx $argv 41 | else 42 | npx --no-install $argv 43 | end 44 | end 45 | 46 | functions --erase __fish_command_not_found_on_interactive 47 | end` 48 | } 49 | 50 | module.exports = autoFallback 51 | function autoFallback (shell, fromEnv, opts) { 52 | if (shell.includes('bash')) { 53 | return mkPosix({isBash: true, install: opts.install}) 54 | } 55 | 56 | if (shell.includes('zsh')) { 57 | return mkPosix({isBash: false, install: opts.install}) 58 | } 59 | 60 | if (shell.includes('fish')) { 61 | return mkFish(opts) 62 | } 63 | 64 | if (fromEnv) { 65 | return autoFallback(fromEnv, null, opts) 66 | } 67 | 68 | console.error(Y`Only Bash, Zsh, and Fish shells are supported :(`) 69 | } 70 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | /README.md 2 | /package.json 3 | /npx.1 4 | /package-lock.json 5 | /node_modules 6 | -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const npx = require('libnpx') 4 | const path = require('path') 5 | 6 | const NPM_PATH = path.join(__dirname, 'node_modules', 'npm', 'bin', 'npm-cli.js') 7 | 8 | const parsed = npx.parseArgs(process.argv, NPM_PATH) 9 | parsed.npxPkg = path.join(__dirname, 'package.json') 10 | npx(parsed) 11 | -------------------------------------------------------------------------------- /bin/package.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npx", 3 | "description": "execute npm package binaries", 4 | "main": "index.js", 5 | "bin": "index.js", 6 | "man": "./npx.1", 7 | "files": [ 8 | "*.js", 9 | "npx.1" 10 | ], 11 | "keywords": [ 12 | "npm", 13 | "npm exec", 14 | "shell", 15 | "scripts", 16 | "npm bin", 17 | "cli" 18 | ], 19 | "repository": "https://github.com/zkat/npx", 20 | "author": { 21 | "name": "Kat Marchán", 22 | "email": "kzm@sykosomatic.org", 23 | "twitter": "maybekatz" 24 | }, 25 | "license": "ISC", 26 | "dependencies": { 27 | "npm": "5.1.0", 28 | "libnpx": "" 29 | }, 30 | "bundleDependencies": [ 31 | "npm", 32 | "libnpx" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /child.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const cp = require('child_process') 4 | const path = require('path') 5 | 6 | module.exports.runCommand = runCommand 7 | function runCommand (command, opts) { 8 | const cmd = opts.call || command || opts.command 9 | const copts = (opts.call ? [] : opts.cmdOpts) || [] 10 | return spawn(cmd, copts, { 11 | shell: opts.shell || !!opts.call, 12 | stdio: opts.stdio || 'inherit' 13 | }).catch(err => { 14 | if (err.code === 'ENOENT') { 15 | err = new Error( 16 | `npx: ${ 17 | require('./y.js')`command not found: ${path.basename(cmd)}` 18 | }` 19 | ) 20 | err.exitCode = 127 21 | } else { 22 | err.message = require('./y.js')`Command failed: ${cmd} ${err.message}` 23 | } 24 | throw err 25 | }) 26 | } 27 | 28 | module.exports.spawn = spawn 29 | function spawn (cmd, args, opts) { 30 | opts = opts || {} 31 | opts.shell = opts.shell || process.platform === 'win32' 32 | return new Promise((resolve, reject) => { 33 | const child = cp.spawn(cmd, args, opts) 34 | let stdout = '' 35 | let stderr = '' 36 | child.stdout && child.stdout.on('data', d => { stdout += d }) 37 | child.stderr && child.stderr.on('data', d => { stderr += d }) 38 | child.on('error', reject) 39 | child.on('close', code => { 40 | if (code) { 41 | const err = new Error( 42 | require('./y.js')`Command failed: ${cmd} ${args.join(' ')}` 43 | ) 44 | err.isOperational = true 45 | err.stderr = stderr 46 | err.exitCode = code 47 | reject(err) 48 | } else { 49 | resolve({code, stdout, stderr}) 50 | } 51 | }) 52 | }) 53 | } 54 | 55 | module.exports.exec = exec 56 | function exec (cmd, args, opts) { 57 | opts = opts || {} 58 | return new Promise((resolve, reject) => { 59 | cp.exec(`${escapeArg(cmd, true)} ${ 60 | args.join(' ') 61 | }`, opts, (err, stdout) => { 62 | if (err) { 63 | if (typeof err.code === 'number') { 64 | err.exitCode = err.code 65 | } 66 | reject(err) 67 | } else { 68 | resolve(stdout) 69 | } 70 | }) 71 | }) 72 | } 73 | 74 | module.exports.escapeArg = escapeArg 75 | function escapeArg (str, asPath) { 76 | return process.platform === 'win32' && asPath 77 | ? path.normalize(str) 78 | .split(/\\/) 79 | .map(s => s.match(/\s+/) ? `"${s}"` : s) 80 | .join('\\') 81 | : process.platform === 'win32' 82 | ? `"${str}"` 83 | : str.match(/[^-_.~/\w]/) 84 | ? `'${str.replace(/'/g, "'\"'\"'")}'` 85 | : str 86 | } 87 | -------------------------------------------------------------------------------- /get-prefix.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const promisify = require('./util.js').promisify 4 | 5 | const path = require('path') 6 | const statAsync = promisify(require('fs').stat) 7 | 8 | module.exports = getPrefix 9 | function getPrefix (root) { 10 | const original = root = path.resolve(root) 11 | while (path.basename(root) === 'node_modules') { 12 | root = path.dirname(root) 13 | } 14 | if (original !== root) { 15 | return Promise.resolve(root) 16 | } else { 17 | return Promise.resolve(getPrefixFromTree(root)) 18 | } 19 | } 20 | 21 | function getPrefixFromTree (current) { 22 | if (isRootPath(current, process.platform)) { 23 | return false 24 | } else { 25 | return Promise.all([ 26 | fileExists(path.join(current, 'package.json')), 27 | fileExists(path.join(current, 'node_modules')) 28 | ]).then(args => { 29 | const hasPkg = args[0] 30 | const hasModules = args[1] 31 | if (hasPkg || hasModules) { 32 | return current 33 | } else { 34 | return getPrefixFromTree(path.dirname(current)) 35 | } 36 | }) 37 | } 38 | } 39 | 40 | module.exports._fileExists = fileExists 41 | function fileExists (f) { 42 | return statAsync(f).catch(err => { 43 | if (err.code !== 'ENOENT') { 44 | throw err 45 | } 46 | }) 47 | } 48 | 49 | module.exports._isRootPath = isRootPath 50 | function isRootPath (p, platform) { 51 | return platform === 'win32' 52 | ? p.match(/^[a-z]+:[/\\]?$/i) 53 | : p === '/' 54 | } 55 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Buffer = require('safe-buffer').Buffer 4 | const promisify = require('./util.js').promisify 5 | 6 | const child = require('./child') 7 | const fs = require('fs') 8 | const parseArgs = require('./parse-args.js') 9 | const path = require('path') 10 | const which = promisify(require('which')) 11 | 12 | module.exports = npx 13 | module.exports.parseArgs = parseArgs 14 | function npx (argv) { 15 | const shell = argv['shell-auto-fallback'] 16 | if (shell || shell === '') { 17 | const fallback = require('./auto-fallback.js')( 18 | shell, process.env.SHELL, argv 19 | ) 20 | if (fallback) { 21 | return console.log(fallback) 22 | } else { 23 | process.exitCode = 1 24 | return 25 | } 26 | } 27 | 28 | if (!argv.call && (!argv.command || !argv.package)) { 29 | !argv.q && console.error(Y()`\nERROR: You must supply a command.\n`) 30 | !argv.q && parseArgs.showHelp() 31 | process.exitCode = 1 32 | return 33 | } 34 | 35 | const startTime = Date.now() 36 | 37 | // First, we look to see if we're inside an npm project, and grab its 38 | // bin path. This is exactly the same as running `$ npm bin`. 39 | return localBinPath(process.cwd()).then(local => { 40 | if (local) { 41 | // Local project paths take priority. Go ahead and prepend it. 42 | process.env.PATH = `${local}${path.delimiter}${process.env.PATH}` 43 | } 44 | return Promise.all([ 45 | // Figuring out if a command exists, early on, lets us maybe 46 | // short-circuit a few things later. This bit here primarily benefits 47 | // calls like `$ npx foo`, where we might just be trying to invoke 48 | // a single command and use whatever is already in the path. 49 | argv.command && getExistingPath(argv.command, argv), 50 | // The `-c` flag involves special behavior when used: in this case, 51 | // we take a bit of extra time to pick up npm's full lifecycle script 52 | // environment (so you can use `$npm_package_xxxxx` and company). 53 | // Without that flag, we just use the current env. 54 | argv.call && local && getEnv(argv) 55 | ]).then(args => { 56 | const existing = args[0] 57 | const newEnv = args[1] 58 | if (newEnv) { 59 | // NOTE - we don't need to manipulate PATH further here, because 60 | // npm has already done so. And even added the node-gyp path! 61 | Object.assign(process.env, newEnv) 62 | } 63 | if ((!existing && !argv.call) || argv.packageRequested) { 64 | // We only fire off the updateNotifier if we're installing things 65 | if (argv.npxPkg) { 66 | try { 67 | require('update-notifier')({ 68 | pkg: require(argv.npxPkg) 69 | }).notify() 70 | } catch (e) {} 71 | } 72 | // Some npm packages need to be installed. Let's install them! 73 | return ensurePackages(argv.package, argv).then(results => { 74 | if (results && results.added && results.updated && !argv.q) { 75 | console.error(Y()`npx: installed ${ 76 | results.added.length + results.updated.length 77 | } in ${(Date.now() - startTime) / 1000}s`) 78 | } 79 | if ( 80 | argv.command && 81 | !existing && 82 | !argv.packageRequested && 83 | argv.package.length === 1 84 | ) { 85 | return promisify(fs.readdir)(results.bin).then(bins => { 86 | if (process.platform === 'win32') { 87 | bins = bins.filter(b => b !== 'etc' && b !== 'node_modules') 88 | } 89 | if (bins.length < 1) { 90 | throw new Error(Y()`command not found: ${argv.command}`) 91 | } 92 | const cmd = new RegExp(`^${argv.command}(?:\\.cmd)?$`, 'i') 93 | const matching = bins.find(b => b.match(cmd)) 94 | return path.resolve(results.bin, bins[matching] || bins[0]) 95 | }, err => { 96 | if (err.code === 'ENOENT') { 97 | throw new Error(Y()`command not found: ${argv.command}`) 98 | } else { 99 | throw err 100 | } 101 | }) 102 | } else { 103 | return existing 104 | } 105 | }) 106 | } else { 107 | // We can skip any extra installation, 'cause everything exists. 108 | return existing 109 | } 110 | }).then(existing => { 111 | return execCommand(existing, argv) 112 | }).catch(err => { 113 | !argv.q && console.error(err.message) 114 | process.exitCode = err.exitCode || 1 115 | }) 116 | }) 117 | } 118 | 119 | module.exports._localBinPath = localBinPath 120 | function localBinPath (cwd) { 121 | return require('./get-prefix.js')(cwd).then(prefix => { 122 | return prefix && path.join(prefix, 'node_modules', '.bin') 123 | }) 124 | } 125 | 126 | module.exports._getEnv = getEnv 127 | function getEnv (opts) { 128 | const args = ['run', 'env', '--parseable'] 129 | return findNodeScript(opts.npm, {isLocal: true}).then(npmPath => { 130 | if (npmPath) { 131 | args.unshift(child.escapeArg(opts.npm)) 132 | return process.argv[0] 133 | } else { 134 | return opts.npm 135 | } 136 | }).then(npmPath => { 137 | return child.exec(npmPath, args) 138 | }).then(require('dotenv').parse) 139 | } 140 | 141 | module.exports._ensurePackages = ensurePackages 142 | function ensurePackages (specs, opts) { 143 | return ( 144 | opts.cache ? Promise.resolve(opts.cache) : getNpmCache(opts) 145 | ).then(cache => { 146 | const prefix = path.join(cache, '_npx', process.pid.toString()) 147 | const bins = process.platform === 'win32' 148 | ? prefix 149 | : path.join(prefix, 'bin') 150 | const rimraf = require('rimraf') 151 | process.on('exit', () => rimraf.sync(prefix)) 152 | return promisify(rimraf)(bins).then(() => { 153 | return installPackages(specs, prefix, opts) 154 | }).then(info => { 155 | // This will make temp bins _higher priority_ than even local bins. 156 | // This is intentional, since npx assumes that if you went through 157 | // the trouble of doing `-p`, you're rather have that one. Right? ;) 158 | process.env.PATH = `${bins}${path.delimiter}${process.env.PATH}` 159 | if (!info) { info = {} } 160 | info.prefix = prefix 161 | info.bin = bins 162 | return info 163 | }) 164 | }) 165 | } 166 | 167 | module.exports._getExistingPath = getExistingPath 168 | function getExistingPath (command, opts) { 169 | if (opts.isLocal) { 170 | return Promise.resolve(command) 171 | } else if ( 172 | opts.cmdHadVersion || opts.packageRequested || opts.ignoreExisting 173 | ) { 174 | return Promise.resolve(false) 175 | } else { 176 | return which(command).catch(err => { 177 | if (err.code === 'ENOENT') { 178 | if (opts.install === false) { 179 | err.exitCode = 127 180 | throw err 181 | } 182 | } else { 183 | throw err 184 | } 185 | }) 186 | } 187 | } 188 | 189 | module.exports._getNpmCache = getNpmCache 190 | function getNpmCache (opts) { 191 | const args = ['config', 'get', 'cache', '--parseable'] 192 | if (opts.userconfig) { 193 | args.push('--userconfig', child.escapeArg(opts.userconfig, true)) 194 | } 195 | return findNodeScript(opts.npm, {isLocal: true}).then(npmPath => { 196 | if (npmPath) { 197 | // This one is NOT escaped as a path because it's handed to Node. 198 | args.unshift(child.escapeArg(opts.npm)) 199 | return process.argv[0] 200 | } else { 201 | return opts.npm 202 | } 203 | }).then(npmPath => { 204 | return child.exec(npmPath, args) 205 | }).then(cache => cache.trim()) 206 | } 207 | 208 | module.exports._buildArgs = buildArgs 209 | function buildArgs (specs, prefix, opts) { 210 | const args = ['install'].concat(specs) 211 | args.push('--global', '--prefix', prefix) 212 | if (opts.cache) args.push('--cache', opts.cache) 213 | if (opts.userconfig) args.push('--userconfig', opts.userconfig) 214 | args.push('--loglevel', 'error', '--json') 215 | 216 | return args 217 | } 218 | 219 | module.exports._installPackages = installPackages 220 | function installPackages (specs, prefix, opts) { 221 | const args = buildArgs(specs, prefix, opts) 222 | return findNodeScript(opts.npm, {isLocal: true}).then(npmPath => { 223 | if (npmPath) { 224 | args.unshift( 225 | process.platform === 'win32' 226 | ? child.escapeArg(opts.npm) 227 | : opts.npm 228 | ) 229 | return process.argv[0] 230 | } else { 231 | return opts.npm 232 | } 233 | }).then(npmPath => { 234 | return process.platform === 'win32' ? child.escapeArg(npmPath, true) : npmPath 235 | }).then(npmPath => { 236 | return child.spawn(npmPath, args, { 237 | stdio: opts.installerStdio 238 | ? opts.installerStdio 239 | : [0, 'pipe', opts.q ? 'ignore' : 2] 240 | }).then(deets => { 241 | try { 242 | return deets.stdout ? JSON.parse(deets.stdout) : null 243 | } catch (e) { } 244 | }, err => { 245 | if (err.exitCode) { 246 | err.message = Y()`Install for ${specs} failed with code ${err.exitCode}` 247 | } 248 | throw err 249 | }) 250 | }) 251 | } 252 | 253 | module.exports._execCommand = execCommand 254 | function execCommand (_existing, argv) { 255 | return findNodeScript(_existing, argv).then(existing => { 256 | const argvCmdOpts = argv.cmdOpts || [] 257 | if (existing && !argv.alwaysSpawn && !argv.nodeArg && !argv.shell && existing !== process.argv[1]) { 258 | const Module = require('module') 259 | // let it take over the process. This means we can skip node startup! 260 | if (!argv.noYargs) { 261 | // blow away built-up yargs crud 262 | require('yargs').reset() 263 | } 264 | process.argv = [ 265 | process.argv[0], // Current node binary 266 | existing // node script path. `runMain()` will set this as the new main 267 | ].concat(argvCmdOpts) // options for the cmd itself 268 | Module.runMain() // ✨MAGIC✨. Sorry-not-sorry 269 | } else if (!existing && argv.nodeArg && argv.nodeArg.length) { 270 | throw new Error(Y()`ERROR: --node-arg/-n can only be used on packages with node scripts.`) 271 | } else { 272 | let cmd = existing 273 | let cmdOpts = argvCmdOpts 274 | if (existing) { 275 | cmd = process.argv[0] 276 | if (process.platform === 'win32') { 277 | cmd = child.escapeArg(cmd, true) 278 | } 279 | // If we know we're running a run script and we got a --node-arg, 280 | // we need to fudge things a bit to get them working right. 281 | cmdOpts = argv.nodeArg 282 | if (cmdOpts) { 283 | cmdOpts = Array.isArray(cmdOpts) ? cmdOpts : [cmdOpts] 284 | } else { 285 | cmdOpts = [] 286 | } 287 | // It's valid for a single arg to be a string of multiple 288 | // space-separated node args. 289 | // Example: `$ npx -n '--inspect --harmony --debug' ...` 290 | cmdOpts = cmdOpts.reduce((acc, arg) => { 291 | return acc.concat(arg.split(/\s+/)) 292 | }, []) 293 | cmdOpts = cmdOpts.concat(existing, argvCmdOpts) 294 | } 295 | const opts = Object.assign({}, argv, { cmdOpts }) 296 | return child.runCommand(cmd, opts).catch(err => { 297 | if (err.isOperational && err.exitCode) { 298 | // At this point, we want to treat errors from the child as if 299 | // we were just running the command. That means no extra msg logging 300 | process.exitCode = err.exitCode 301 | } else { 302 | // But if it's not just a regular child-level error, blow up normally 303 | throw err 304 | } 305 | }) 306 | } 307 | }) 308 | } 309 | 310 | module.exports._findNodeScript = findNodeScript 311 | function findNodeScript (existing, opts) { 312 | if (!existing) { 313 | return Promise.resolve(false) 314 | } else { 315 | return promisify(fs.stat)(existing).then(stat => { 316 | if (opts && opts.isLocal && path.extname(existing) === '.js') { 317 | return existing 318 | } else if (opts && opts.isLocal && stat.isDirectory()) { 319 | // npx will execute the directory itself 320 | try { 321 | const pkg = require(path.resolve(existing, 'package.json')) 322 | const target = path.resolve(existing, pkg.bin || pkg.main || 'index.js') 323 | return findNodeScript(target, opts).then(script => { 324 | if (script) { 325 | return script 326 | } else { 327 | throw new Error(Y()`command not found: ${target}`) 328 | } 329 | }) 330 | } catch (e) { 331 | throw new Error(Y()`command not found: ${existing}`) 332 | } 333 | } else if (process.platform !== 'win32') { 334 | const bytecount = 400 335 | const buf = Buffer.alloc(bytecount) 336 | return promisify(fs.open)(existing, 'r').then(fd => { 337 | return promisify(fs.read)(fd, buf, 0, bytecount, 0).then(() => { 338 | return promisify(fs.close)(fd) 339 | }, err => { 340 | return promisify(fs.close)(fd).then(() => { throw err }) 341 | }) 342 | }).then(() => { 343 | const re = /#!\s*(?:\/usr\/bin\/env\s*node|\/usr\/local\/bin\/node|\/usr\/bin\/node)\s*\r?\n/i 344 | return buf.toString('utf8').match(re) && existing 345 | }) 346 | } else if (process.platform === 'win32') { 347 | const buf = Buffer.alloc(1000) 348 | return promisify(fs.open)(existing, 'r').then(fd => { 349 | return promisify(fs.read)(fd, buf, 0, 1000, 0).then(() => { 350 | return promisify(fs.close)(fd) 351 | }, err => { 352 | return promisify(fs.close)(fd).then(() => { throw err }) 353 | }) 354 | }).then(() => { 355 | return buf.toString('utf8').trim() 356 | }).then(str => { 357 | const cmd = /"%~dp0\\node\.exe"\s+"%~dp0\\(.*)"\s+%\*/ 358 | const mingw = /"\$basedir\/node"\s+"\$basedir\/(.*)"\s+"\$@"/i 359 | return str.match(cmd) || str.match(mingw) 360 | }).then(match => { 361 | return match && path.join(path.dirname(existing), match[1]) 362 | }) 363 | } 364 | }) 365 | } 366 | } 367 | 368 | function Y () { 369 | return require('./y.js') 370 | } 371 | -------------------------------------------------------------------------------- /locales/ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Executa comandes de paquets de npm.\n%s", 3 | "Package to be installed.": "Paquet per a instal·lar.", 4 | "Location of the npm cache.": "Ruta de la memòria cau de npm.", 5 | "Skip installation if a package is missing.": "Salta el pas d'instal·lació si el paquet no està present.", 6 | "Path to user npmrc.": "Ruta al npmrc de l'usuari.", 7 | "Execute string as if inside `npm run-script`.": "Executa l'argument com si estigués dins de `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell amb el qual s'executarà la comanda, si hi ha algun.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Genera codi de shell per utilizar npx com el replegament quan la comanda no existeix.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignora comandaments en $PATH, o en el projecte local. Això obliga a npx a fer una instal·lació temporal i usar la versió més recent de la comanda.", 11 | "npm binary to use for internal operations.": "Comando d'npm que es farà servir per a operacions internes de npx.", 12 | "For the full documentation, see the manual page for npx(1).": "Per documentació completa, vegeu la pàgina del manual npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "No s'ha pogut endevinar el nom de la comanda usant %s. Si us plau utilitza --package.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: Has proveir una comanda.\n", 15 | "Command failed: %s %s": "La comanda va fracasar: %s %s", 16 | "Install for %s failed with code %s": "instal·lació de %s fracassar amb codi %s", 17 | "%s not found. Trying with npx...": "%s no existeix. Provant-ho amb npx...", 18 | "command not found: %s": "comanda no existeix: %s", 19 | "options": "opcions", 20 | "command": "comanda", 21 | "version": "versió", 22 | "command-arg": "argument-de-comanda", 23 | "command-string": "text-de-comanda", 24 | "shell": "shell", 25 | "package": "paquet", 26 | "npx: installed %s in %ss": "npx: instal·lat %s en %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Suprimir la sortida d' npx. Les sub-comandes no es veuran afectades." 28 | } 29 | -------------------------------------------------------------------------------- /locales/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Spouštění skriptů z npm balíčků.\n%s", 3 | "Package to be installed.": "Balíček k instalaci.", 4 | "Location of the npm cache.": "Umístění npm keše.", 5 | "Skip installation if a package is missing.": "Neinstalovat chybějící balíčky.", 6 | "Path to user npmrc.": "Cesta k uživatelskému npmrc souboru.", 7 | "Execute string as if inside `npm run-script`.": "Příkaz, který se spustí jakoby uvnitř `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell ke spuštění příkazu, pokud je třeba.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Vygenerovat shell kód použitelný jako \"command not found\" fallback.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignorovat existující skripty v $PATH i v lokálním projektu, npx tak udělá dočasnou instalaci a použije poslední verzi balíčku.", 11 | "npm binary to use for internal operations.": "npm použité pro interní operace.", 12 | "For the full documentation, see the manual page for npx(1).": "Úplná dokumentace je dostupná v manuálu pro npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Nelze uhodnout jméno skriptu z %s, použijte prosím --package.", 14 | "\nERROR: You must supply a command.\n": "\nCHYBA: Musíte zadat nějaký příkaz.\n", 15 | "Command failed: %s %s": "Příkaz selhal: %s %s", 16 | "Install for %s failed with code %s": "Instalace %s selhala s kódem %s", 17 | "%s not found. Trying with npx...": "%s nenalezen. Zkouším npx...", 18 | "command not found: %s": "příkaz nenalezen: %s", 19 | "options": "parametry", 20 | "command": "příkaz", 21 | "version": "verze", 22 | "command-arg": "argument", 23 | "command-string": "příkaz v řetězci", 24 | "shell": "shell", 25 | "package": "balíček", 26 | "npx: installed %s in %ss": "npx: nainstalováno %s za %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Potlačit výstup z npx. Spuštěné příkazy nebudou ovlivněné." 28 | } 29 | -------------------------------------------------------------------------------- /locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Führt Programme aus, die von npm Paketen bereitgestellt werden.\n%s", 3 | "Package to be installed.": "Das zu installierende Paket.", 4 | "Location of the npm cache.": "Ort des npm Zwischenspeichers.", 5 | "Skip installation if a package is missing.": "Überspringe die Installation, falls ein Paket fehlt.", 6 | "Path to user npmrc.": "Pfad zu npmrc im Benutzerverzeichnis.", 7 | "Execute string as if inside `npm run-script`.": "Führe Zeichenkette aus, als wäre sie innerhalb von `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell, mit der Programme ausgeführt werden soll, wenn überhaupt.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Erzeuge Shellcode, um npx als Alternative zu \"Programm konnte nicht gefunden werden\" zu benutzen.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignoriere bestehende Programme innerhalb von $PATH oder im lokalen Projekt. Dies zwingt npx dazu, die neuste Version herunterzuladen und zu benutzen.", 11 | "npm binary to use for internal operations.": "npm-Programm für die interne Benutzung.", 12 | "For the full documentation, see the manual page for npx(1).": "In der Manpage npx(1) ist die gesamte Dokumentation einzusehen.", 13 | "Unable to guess a binary name from %s. Please use --package.": "Der Programmname von %s kann nicht automatisch ermittelt werden. Bitte benutze --package.", 14 | "\nERROR: You must supply a command.\n": "\nFEHLER: Du musst einen Befehl angeben.\n", 15 | "Command failed: %s %s": "Befehl fehlgeschlagen: %s %s", 16 | "Install for %s failed with code %s": "Die Installation von %s ist mit dem Code %s fehlgeschlagen", 17 | "%s not found. Trying with npx...": "%s konnte nicht gefunden werden. Versuche mit npx...", 18 | "command not found: %s": "Programm konnte nicht gefunden werden: %s", 19 | "options": "Optionen", 20 | "command": "Befehl", 21 | "version": "Version", 22 | "command-arg": "Befehlsargument", 23 | "command-string": "Befehlszeichenkette", 24 | "shell": "Shell", 25 | "package": "Paket", 26 | "npx: installed %s in %ss": "npx: Installierte %s in %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Unterdrücke Output von npx. Unterbefehle sind nicht davon betroffen.", 28 | "Extra node argument when calling a node binary.": "Extra node Argument, wenn eine node ausführbare Binärdatei gerufen ist." 29 | } 30 | -------------------------------------------------------------------------------- /locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Execute binaries from npm packages.\n%s", 3 | "Package to be installed.": "Package to be installed.", 4 | "Location of the npm cache.": "Location of the npm cache.", 5 | "Skip installation if a package is missing.": "Skip installation if a package is missing.", 6 | "Path to user npmrc.": "Path to user npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Execute string as if inside `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell to execute the command with, if any.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Generate shell code to use npx as the \"command not found\" fallback.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.", 11 | "npm binary to use for internal operations.": "npm binary to use for internal operations.", 12 | "For the full documentation, see the manual page for npx(1).": "For the full documentation, see the manual page for npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Unable to guess a binary name from %s. Please use --package.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: You must supply a command.\n", 15 | "Command failed: %s %s": "Command failed: %s %s", 16 | "Install for %s failed with code %s": "Install for %s failed with code %s", 17 | "%s not found. Trying with npx...": "%s not found. Trying with npx...", 18 | "command not found: %s": "command not found: %s", 19 | "options": "options", 20 | "command": "command", 21 | "version": "version", 22 | "command-arg": "command-arg", 23 | "command-string": "command-string", 24 | "shell": "shell", 25 | "package": "package", 26 | "npx: installed %s in %ss": "npx: installed %s in %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Suppress output from npx itself. Subcommands will not be affected.", 28 | "Extra node argument when calling a node binary.": "Extra node argument when calling a node binary.", 29 | "Always spawn a child process to execute the command.": "Always spawn a child process to execute the command." 30 | } -------------------------------------------------------------------------------- /locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Ejecuta comandos de paquetes de npm.\n%s", 3 | "Package to be installed.": "Paquete para instalar.", 4 | "Location of the npm cache.": "Ruta del cache de npm.", 5 | "Skip installation if a package is missing.": "Salta el paso de instalación si el paquete no está presente.", 6 | "Path to user npmrc.": "Ruta al npmrc del usuario.", 7 | "Execute string as if inside `npm run-script`.": "Ejecuta el argumento como si estuviera dentro de `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell con el que se ejecutará el comando, si alguno.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Genera código de shell para usar npx como el repliegue cuando el comando no existe.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignora comandos en $PATH, o en el proyecto local. Esto obliga a npx a hacer una instalación temporanea y usar la version más reciente del comando.", 11 | "npm binary to use for internal operations.": "Comando de npm que se usará para operaciones internas de npx.", 12 | "For the full documentation, see the manual page for npx(1).": "Para documentación completa, véase la pagina del manual npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "No se pudo adivinar el nombre del comando usando %s. Por favor usa --package.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: Debes proveer un comando.\n", 15 | "Command failed: %s %s": "Comando fracasó: %s %s", 16 | "Install for %s failed with code %s": "La instalación de %s fracasó con código %s", 17 | "%s not found. Trying with npx...": "%s no existe. Tratando con npx...", 18 | "command not found: %s": "comando no existe: %s", 19 | "options": "opciones", 20 | "command": "comando", 21 | "version": "versión", 22 | "command-arg": "argumento-de-comando", 23 | "command-string": "texto-de-comando", 24 | "shell": "shell", 25 | "package": "paquete", 26 | "npx: installed %s in %ss": "npx: instaló %s en %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Suprimir producción de npx. Sub-comandos no serán afectados." 28 | } 29 | -------------------------------------------------------------------------------- /locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Exécutez des binaires à partir de paquets npm.\n%s", 3 | "Package to be installed.": "Paquet à installer.", 4 | "Location of the npm cache.": "Chemin où est situé le cache de npm.", 5 | "Skip installation if a package is missing.": "Passer l'installation si un paquet est manquant.", 6 | "Path to user npmrc.": "Chemin du fichier npmrc de l'utilisateur(-trice).", 7 | "Execute string as if inside `npm run-script`.": "Exécuter la chaine de caractère comme avec `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell à utiliser pour exécuter la commande, s'il y en a un.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Générer le code du shell pour utiliser npx comme solution de rechange à \"command not found\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignorer les binaires dans le $PATH ou dans le projet local. Cela force npm à réaliser une installation temporaire et à utiliser la dernière version.", 11 | "npm binary to use for internal operations.": "Binaire de npm à utiliser pour les opérations internes.", 12 | "For the full documentation, see the manual page for npx(1).": "Pour la documentation complète, consultez la page du manuel pour npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Impossible de deviner le nom du binaire de %s, utilisez --package s'il vous plaît.", 14 | "\nERROR: You must supply a command.\n": "\nERREUR : Vous devez fournir une commande.\n", 15 | "Command failed: %s %s": "La commande a échoué : %s %s", 16 | "Install for %s failed with code %s": "L'installation de %s a échoué avec le code %s", 17 | "%s not found. Trying with npx...": "%s n'a pas été trouvé. Essai avec npx...", 18 | "command not found: %s": "Commande non trouvée : %s", 19 | "options": "options", 20 | "command": "commande", 21 | "version": "version", 22 | "command-arg": "arguments-de-la-commande", 23 | "command-string": "chaîne-de-caractères-de-la-commande", 24 | "shell": "shell", 25 | "package": "paquet", 26 | "npx: installed %s in %ss": "npx : %s installé(s) en %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Supprimer la sortie générée par npx. Les sous-commandes ne seront pas affectées." 28 | } 29 | -------------------------------------------------------------------------------- /locales/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Jalankan berkas-berkas binari darpi paket-paket npm.\n%s", 3 | "Package to be installed.": "Paket yang akan dipasang.", 4 | "Location of the npm cache.": "Lokasi dari cache npm.", 5 | "Skip installation if a package is missing.": "Lewati pemasangan jika paket tidak ditemukan.", 6 | "Path to user npmrc.": "Jalur ke npmrc milik pengguna.", 7 | "Execute string as if inside `npm run-script`.": "Jalankan string seperti ada di dalam `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell untuk menjalankan sebuah perintah, jika ada.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Membangkitkan kode shell untuk menggunakan npx sebagai cadangan dari \"perintah tidak ditemukan\" .", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Jangan hiraukan berkas-berkas binari yang ada di $PATH, atau yang ada di proyek lokal. Ini memaksa npx untuk melakukan pemasangan sementara dan menggunakan versi yang terakhir.", 11 | "npm binary to use for internal operations.": "Binari npm yang digunakan untuk operasi internal.", 12 | "For the full documentation, see the manual page for npx(1).": "Untuk dokumentasi lengkap, mohon baca laman manual untuk npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Tidak dapat menebak nama binari dari %s. Mohon gunakan --package.", 14 | "\nERROR: You must supply a command.\n": "\nGALAT: Anda harus menyediakan sebuah perintah.\n", 15 | "Command failed: %s %s": "Perintah tidak berhasil: %s %s", 16 | "Install for %s failed with code %s": "Pemasangan untuk %s tidak berhasil dengan kode %s", 17 | "%s not found. Trying with npx...": "%s tidak ditemukan. Mencoba dengan npx...", 18 | "command not found: %s": "Perintah tidak ditemukan: %s", 19 | "options": "opsi-opsi", 20 | "command": "perintah", 21 | "version": "versi", 22 | "command-arg": "arg-perintah", 23 | "command-string": "string-perintah", 24 | "shell": "shell", 25 | "package": "paket", 26 | "npx: installed %s in %ss": "npx: %s terpasang di %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Hilangkan keluaran dari npx itu sendiri. Sub-sub perintah tidak akan terpengaruh.", 28 | "Extra node argument when calling a node binary.": "Argumen node ekstra ketika memanggil binari node." 29 | } -------------------------------------------------------------------------------- /locales/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Esegui il binario del pacchetto npm.\n%s", 3 | "Package to be installed.": "Pacchetto da installare.", 4 | "Location of the npm cache.": "Percorso della cache npm.", 5 | "Skip installation if a package is missing.": "Salta l'installazione se un pacchetto non è disponibile.", 6 | "Path to user npmrc.": "Percorso utente per npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Esegui l'argomento come se fosse all'interno di `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell con cui eseguire il comando, se presente.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Generare un codice di shell per usare npx come ripiego quando il comando non esiste.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignora i binari esistenti in $PATH, oppure nel progetto locale. Questo forza temporaneamente npx a installare e usare l'ultima versione.", 11 | "npm binary to use for internal operations.": "Binario npm da usare per le operazioni interne.", 12 | "For the full documentation, see the manual page for npx(1).": "Per la documentazione completa, vedere la pagina del manuale npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Impossibile supporre il nome del binario da %s. Prego usare --package.", 14 | "\nERROR: You must supply a command.\n": "\nERRORE: E necessario fornire un comando.\n", 15 | "Command failed: %s %s": "Comando fallito: %s %s", 16 | "Install for %s failed with code %s": "Installazione di %s fallita con codice %s", 17 | "%s not found. Trying with npx...": "%s non trovato. Prova con npx...", 18 | "command not found: %s": "comando non trovato: %s", 19 | "options": "opzioni", 20 | "command": "comando", 21 | "version": "versione", 22 | "command-arg": "argomento-del-comando", 23 | "command-string": "stringa-di-comando", 24 | "shell": "shell", 25 | "package": "pacchetto", 26 | "npx: installed %s in %ss": "npx: installato %s in %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Sopprimere l'output da npx stesso. I sottocomandi non saranno interessati." 28 | } 29 | -------------------------------------------------------------------------------- /locales/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "npmパッケージのバイナリを実行します。", 3 | "Package to be installed.": "インストールするパッケージ。", 4 | "Location of the npm cache.": "npmのキャッシュへのパス。", 5 | "Skip installation if a package is missing.": "パッケージがない場合は、インストールをスキップします。", 6 | "Path to user npmrc.": "ユーザーのnpmrcへのパス。", 7 | "Execute string as if inside `npm run-script`.": "「npm run-script」の内部にあるかのように文字列を実行します。", 8 | "Shell to execute the command with, if any.": "コマンドを実行するシェル(存在する場合)。", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "\"コマンドが見つかりません\" フォールバックとして使用するコードを生成します。", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "$PATH、または既存のローカルプロジェクトのバイナリを無視します。 これにより、npxは一時的にインストールを行い、最新バージョンを使用します。", 11 | "npm binary to use for internal operations.": "npmのバイナリを内部操作に使用します。", 12 | "For the full documentation, see the manual page for npx(1).": "詳しくは、npx(1)のマニュアルページを参照してください。", 13 | "Unable to guess a binary name from %s. Please use --package.": "%sからバイナリ名を推測できません。 --packageを使用してください。", 14 | "\nERROR: You must supply a command.\n": "\nエラー: コマンドを入力する必要があります。\n", 15 | "Command failed: %s %s": "コマンドが失敗しました: %s %s", 16 | "Install for %s failed with code %s": "コード%sで%sのインストールに失敗しました", 17 | "%s not found. Trying with npx...": "%sが見つかりません。 npxで試してみて...", 18 | "command not found: %s": "コマンドが見つかりません: %s", 19 | "options": "オプション", 20 | "command": "コマンド", 21 | "version": "バージョン", 22 | "command-arg": "コマンドの引数", 23 | "command-string": "コマンドの文字列", 24 | "shell": "シェル", 25 | "package": "パッケージ", 26 | "npx: installed %s in %ss": "npx: %s個のパッケージを%s秒でインストールしました。", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "npx自体の標準出力を抑止します。 サブコマンドは影響を受けません。" 28 | } 29 | -------------------------------------------------------------------------------- /locales/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "npm 패키지에서 바이너리를 실행합니다.\n%s", 3 | "Package to be installed.": "설치할 패키지.", 4 | "Location of the npm cache.": "npm 캐시의 위치.", 5 | "Skip installation if a package is missing.": "패키지가 없으면 설치를 건너뜁니다.", 6 | "Path to user npmrc.": "사용자 npmrc의 경로.", 7 | "Execute string as if inside `npm run-script`.": "문자열이 `npm run-script`안에 있는 것처럼 실행합니다.", 8 | "Shell to execute the command with, if any.": "명령을 실행할 셸 (존재하는 경우).", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "\"명령을 찾을 수 없습니다\" 대신 npx가 사용되도록 셸 코드를 생성합니다.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "$PATH나 로컬 프로젝트에 있는 바이너리를 무시합니다. 이는 npx가 최신 버전을 임시로 설치해서 사용하도록 강제합니다.", 11 | "npm binary to use for internal operations.": "내부 작업에 사용할 npm 바이너리.", 12 | "For the full documentation, see the manual page for npx(1).": "전체 문서는 npx(1) 매뉴얼 페이지를 보세요.", 13 | "Unable to guess a binary name from %s. Please use --package.": "%s에서 바이너리 이름을 추측할 수 없습니다. --package를 사용해 주세요.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: 명령을 제공해야 합니다.\n", 15 | "Command failed: %s %s": "명령이 실패했습니다: %s %s", 16 | "Install for %s failed with code %s": "%s 설치가 오류 코드 %s로 실패했습니다", 17 | "%s not found. Trying with npx...": "%s 을 찾을 수 없습니다. npx로 시도합니다...", 18 | "command not found: %s": "명령을 찾을 수 없습니다: %s", 19 | "options": "옵션", 20 | "command": "명령", 21 | "version": "버전", 22 | "command-arg": "명령-인자", 23 | "command-string": "명령-문자열", 24 | "shell": "셸", 25 | "package": "패키지", 26 | "npx: installed %s in %ss": "npx: %s개의 패키지를 %s초만에 설치했습니다.", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "npx의 출력을 감춥니다. 하위 명령은 영향을 받지 않습니다.", 28 | "Extra node argument when calling a node binary.": "node 바이너리를 호출할 때 사용하는 추가 node 인자." 29 | } 30 | -------------------------------------------------------------------------------- /locales/nb.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Kjør binærfiler fra npm-pakker.\n%s", 3 | "Package to be installed.": "Pakken som skal installeres.", 4 | "Location of the npm cache.": "Hvor npm-cachen er.", 5 | "Skip installation if a package is missing.": "La være å installere dersom pakken mangler.", 6 | "Path to user npmrc.": "Sti til brukerens npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Kjør streng som om den var inni `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Skall å kjøre kommandoen med, hvis noe.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Generer skallkode for å bruke npx som \"kommandoen finnes ikke\" fallback.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignorerer eksisterende binærfiler i $PATH eller i det lokale prosjektet. Dette tvinger npx til å installere siste versjon av pakken midlertidig.", 11 | "npm binary to use for internal operations.": "npm-binærfil som skal brukes for interne operasjoner.", 12 | "For the full documentation, see the manual page for npx(1).": "For hele dokumentasjonen, se brukermanualen for npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Klarer ikke å gjette en binærfils navn ut fra %s. Vennligst bruk --package.", 14 | "\nERROR: You must supply a command.\n": "\nFEIL: Du må legge ved en kommando.\n", 15 | "Command failed: %s %s": "Kommando feilet: %s %s", 16 | "Install for %s failed with code %s": "Installasjon for %s feilet med kode %s", 17 | "%s not found. Trying with npx...": "Kunne ikke finne%s. Prøver med npx...", 18 | "command not found: %s": "kommando ikke funnet: %s", 19 | "options": "innstillinger", 20 | "command": "kommando", 21 | "version": "versjon", 22 | "command-arg": "kommando-argument", 23 | "command-string": "kommando-streng", 24 | "shell": "skall", 25 | "package": "pakke", 26 | "npx: installed %s in %ss": "npx: installerte %s på %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Skjul kommandoer fra npx. Sub-kommandoer vil ikke berøres.", 28 | "Extra node argument when calling a node binary.": "Ekstra node-argument når en node-binærfil blir kalt." 29 | } 30 | -------------------------------------------------------------------------------- /locales/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Voer een programma van een npm package uit.\n%s", 3 | "Package to be installed.": "De te installeren package.", 4 | "Location of the npm cache.": "Plaats van de npm cache.", 5 | "Skip installation if a package is missing.": "Sla installatie over als een package nog niet geïnstalleerd is.", 6 | "Path to user npmrc.": "Pad naar je npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Voer de tekst uit, alsof het `npm run-script` was.", 8 | "Shell to execute the command with, if any.": "De shell te gebruiken met dit commando, indien nodig.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Genereer shell-code als vervanging bij \"command not found\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Negeer bestaande programmas in $PATH, of in het lokale prject. Dit forceert npx om een tijdelijke installatie te doen en de laatste versie te gebruiken.", 11 | "npm binary to use for internal operations.": "npm programma te gebuiken voor interne operaties.", 12 | "For the full documentation, see the manual page for npx(1).": "Voor de volledige documentatie, raadpleeg de man pagina van npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Vond geen programmanaam voor %S. Probeer opnieuw met --package.", 14 | "\nERROR: You must supply a command.\n": "\nFOUT: Je moet een commando ingeven.\n", 15 | "Command failed: %s %s": "Commando mislukt: %s %s", 16 | "Install for %s failed with code %s": "De installatie van %s is mislukt met code %s", 17 | "%s not found. Trying with npx...": "%s werd niet gevonden. Probeert nu met npx…", 18 | "command not found: %s": "programma werd niet gevonden in %s", 19 | "options": "opties", 20 | "command": "commando", 21 | "version": "versie", 22 | "command-arg": "commandoargumenten", 23 | "command-string": "commandotekst", 24 | "shell": "shell", 25 | "package": "package", 26 | "npx: installed %s in %ss": "npx: heeft %s in %ss geïnstalleerd", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Geef geen uitvoer voor npx zelf. Heeft geen invoed op subcommando's", 28 | "Extra node argument when calling a node binary.": "Extra argumenten voor node, wanner een node-programma gebruikt wordt" 29 | } 30 | -------------------------------------------------------------------------------- /locales/nn.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Køyr binærfiler frå npm-pakkar.\n%s", 3 | "Package to be installed.": "Pakken som skal bli installert.", 4 | "Location of the npm cache.": "Kvar npm-mellomlagringa ligg.", 5 | "Skip installation if a package is missing.": "La være å installere viss pakken manglar.", 6 | "Path to user npmrc.": "Sti til brukaren sin npmrc-fil.", 7 | "Execute string as if inside `npm run-script`.": "Køyr streng som om den var inni `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Skall å køyre kommandoen med, viss noe.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Generer skallkode for å bruke npx som \"kommandoen finst ikkje\" fallback.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignorerer eksisterende binærfilar i $PATH eller i det lokale prosjektet. Dette tvingar npx til å installere siste versjon av pakken midlertidig.", 11 | "npm binary to use for internal operations.": "npm-binærfil som skal brukes for interne operasjonar.", 12 | "For the full documentation, see the manual page for npx(1).": "For heile dokumentasjonen, sjå brukarmanualen for npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Klarar ikkje å gjette ein binærfil sitt namn ut frå %s. Vennligst bruk --package.", 14 | "\nERROR: You must supply a command.\n": "\nFEIL: Du må legge ved ein kommando.\n", 15 | "Command failed: %s %s": "Kommando feilte: %s %s", 16 | "Install for %s failed with code %s": "Installasjon for %s feilte med kode %s", 17 | "%s not found. Trying with npx...": "Kunne ikkje finne%s. Prøver med npx...", 18 | "command not found: %s": "kommando ikkje funnet: %s", 19 | "options": "innstillinger", 20 | "command": "kommando", 21 | "version": "versjon", 22 | "command-arg": "kommando-argument", 23 | "command-string": "kommando-streng", 24 | "shell": "skall", 25 | "package": "pakke", 26 | "npx: installed %s in %ss": "npx: installerte %s på %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Skjul kommandoer frå npx. Sub-kommandoer vil ikkje rørast.", 28 | "Extra node argument when calling a node binary.": "Ekstra node-argument når ein node-binærfil blir kalt." 29 | } 30 | -------------------------------------------------------------------------------- /locales/no.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Kjør binærfiler fra npm-pakker.\n%s", 3 | "Package to be installed.": "Pakken som skal installeres.", 4 | "Location of the npm cache.": "Hvor npm-cachen er.", 5 | "Skip installation if a package is missing.": "La være å installere dersom pakken mangler.", 6 | "Path to user npmrc.": "Sti til brukerens npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Kjør streng som om den var inni `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Skall å kjøre kommandoen med, hvis noe.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Generer skallkode for å bruke npx som \"kommandoen finnes ikke\" fallback.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignorerer eksisterende binærfiler i $PATH eller i det lokale prosjektet. Dette tvinger npx til å installere siste versjon av pakken midlertidig.", 11 | "npm binary to use for internal operations.": "npm-binærfil som skal brukes for interne operasjoner.", 12 | "For the full documentation, see the manual page for npx(1).": "For hele dokumentasjonen, se brukermanualen for npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Klarer ikke å gjette en binærfils navn ut fra %s. Vennligst bruk --package.", 14 | "\nERROR: You must supply a command.\n": "\nFEIL: Du må legge ved en kommando.\n", 15 | "Command failed: %s %s": "Kommando feilet: %s %s", 16 | "Install for %s failed with code %s": "Installasjon for %s feilet med kode %s", 17 | "%s not found. Trying with npx...": "Kunne ikke finne%s. Prøver med npx...", 18 | "command not found: %s": "kommando ikke funnet: %s", 19 | "options": "innstillinger", 20 | "command": "kommando", 21 | "version": "versjon", 22 | "command-arg": "kommando-argument", 23 | "command-string": "kommando-streng", 24 | "shell": "skall", 25 | "package": "pakke", 26 | "npx: installed %s in %ss": "npx: installerte %s på %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Skjul kommandoer fra npx. Sub-kommandoer vil ikke berøres.", 28 | "Extra node argument when calling a node binary.": "Ekstra node-argument når en node-binærfil blir kalt." 29 | } 30 | -------------------------------------------------------------------------------- /locales/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Uruchamia pliki wykonywalne (binarki) z paczek npm.\n%s", 3 | "Package to be installed.": "Paczka do zainstalowania.", 4 | "Location of the npm cache.": "Lokalizacja cache npm.", 5 | "Skip installation if a package is missing.": "Pomiń instalacje w przypadku braku paczki.", 6 | "Path to user npmrc.": "Ścieżka do pliku npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Wykonaj polecenie jak gdyby znajdowało się w `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell do wykonania polecenia, jeśli potrzeba.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Wynegeruj kod dla shell-a aby używać npx zamiast \"nie znaleziono polecenia\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignoruje istniejące paczki w $PATH lub lokalnym projekcie. Wymusza na npx tymczasową instalację i użycie najnowszej wersji.", 11 | "npm binary to use for internal operations.": "Ścieżka do binarki npm używanej przez npx.", 12 | "For the full documentation, see the manual page for npx(1).": "Dla pełnej dokumentacji zobacz manual dla npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Nie udało się ustalić binarki dla %s. Proszę użyć --package.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: Musisz podać polecenie.\n", 15 | "Command failed: %s %s": "Polecenie się nie powiodło: %s %s", 16 | "Install for %s failed with code %s": "Instalacja %s nie udała się, kod błędu: %s", 17 | "%s not found. Trying with npx...": "%s: nie znaleziono polecenia. Próba uruchomienia przy użyciu npx...", 18 | "command not found: %s": "nie znaleziono polecenia: %s", 19 | "options": "opcje", 20 | "command": "polecenie", 21 | "version": "wersja", 22 | "command-arg": "argument polecenia", 23 | "command-string": "tekst polecenia", 24 | "shell": "shell", 25 | "package": "paczka", 26 | "npx: installed %s in %ss": "npx: zainstalowano %s w %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Wycisza wyjście z npx. Nie dotyczy podprocesów.", 28 | "Extra node argument when calling a node binary.": "Dodatkowe argumenty przekazywane do node." 29 | } -------------------------------------------------------------------------------- /locales/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Executa comandos de módulos npm.\n%s", 3 | "Package to be installed.": "Pacote para ser instalado.", 4 | "Location of the npm cache.": "Localização da cache npm.", 5 | "Skip installation if a package is missing.": "Pular instalação se um pacote está faltando.", 6 | "Path to user npmrc.": "Localização do npmrc do usuário.", 7 | "Execute string as if inside `npm run-script`.": "Executa string como se estivesse dentro de `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Terminal para executar o comando, se tiver.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Gera código de terminal para usar npx no lugar quando comando não existir (\"command not found\").", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignora comandos no $PATH ou no projeto atual. Isto obriga npx a fazer uma instalação temporária e usar a última versão.", 11 | "npm binary to use for internal operations.": "Comando npm usado para operações internas.", 12 | "For the full documentation, see the manual page for npx(1).": "Para documentação completa, veja a página do manual npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Não foi possível advinhar o nome do comando usando %s. Por favor, use --package.", 14 | "\nERROR: You must supply a command.\n": "\nERRO: Você deve suprir um comando.\n", 15 | "Command failed: %s %s": "Comando fracassou: %s %s", 16 | "Install for %s failed with code %s": "Instalação de %s falhou com código %s", 17 | "%s not found. Trying with npx...": "%s não existe. Tentando com npx...", 18 | "command not found: %s": "comando não existe: %s", 19 | "options": "opções", 20 | "command": "comando", 21 | "version": "versão", 22 | "command-arg": "argumento-de-comando", 23 | "command-string": "string-de-comando", 24 | "shell": "terminal", 25 | "package": "pacote", 26 | "npx: installed %s in %ss": "npx: instalou %s em %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Omitir resultado de npx. Sub-comandos não serão afetados." 28 | } 29 | -------------------------------------------------------------------------------- /locales/ro.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Rulează executabilele binare din pachetele npm.\n%s", 3 | "Package to be installed.": "Pachetul care va fi instalat.", 4 | "Location of the npm cache.": "Locația cache-ului npm.", 5 | "Skip installation if a package is missing.": "Sari peste instalare dacă lipsește un pachet.", 6 | "Path to user npmrc.": "Calea către fișierul npmrc al utilizatorului.", 7 | "Execute string as if inside `npm run-script`.": "Execută string-ul ca și cum ar fi în `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell-ul cu care să fie executată comandă, dacă există.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Generează cod shell pentru a folosi npx drept fallback pentru \"comanda nu a fost găsită\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignoră executabilele binare existente din $PATH, sau din proiectul local. Aceasta forțează npx să facă o instalare temporară și să folosească ultima versiune.", 11 | "npm binary to use for internal operations.": "Executabilul binar npm care să fie folosit pentru operaţiunile interne.", 12 | "For the full documentation, see the manual page for npx(1).": "Pentru documentația completă, vedeți pagina de manual pentru npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Imposibil de ghicit numele executabilului binar pentru %s. Vă rugăm folosiți --package.", 14 | "\nERROR: You must supply a command.\n": "\nEROARE: Trebuie să specifici o comandă.\n", 15 | "Command failed: %s %s": "Comanda a eșuat: %s %s", 16 | "Install for %s failed with code %s": "Procesul de instalare pentru %s a eșuat cu codul %s", 17 | "%s not found. Trying with npx...": "%s nu a fost găsită. Încercare cu npx...", 18 | "command not found: %s": "comanda nu a fost găsită: %s", 19 | "options": "opțiuni", 20 | "command": "comandă", 21 | "version": "versiune", 22 | "command-arg": "comandă-argument", 23 | "command-string": "comandă-string", 24 | "shell": "shell", 25 | "package": "pachet", 26 | "npx: installed %s in %ss": "npx: instalat %s în %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Suprimă outputul de la npx însăși. Subcomenzile nu vor fi afectate." 28 | } 29 | -------------------------------------------------------------------------------- /locales/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Выполняйте скрипты из npm пакетов.\n%s", 3 | "Package to be installed.": "Пакет, который будет установлен.", 4 | "Location of the npm cache.": "Расположение npm кеша.", 5 | "Skip installation if a package is missing.": "Пропустить установку, если пакет отсутствует.", 6 | "Path to user npmrc.": "Передать пользователя в npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Выполнить скрипт как внутри `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell, чтобы выполнить команду, если необходимо.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Создает код для shell, чтобы использовать npx при \"command not found\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Игнорирует все существующие скрипты в $PATH или локальном проекте. Что заставляет npx использовать временную установку и использовать последние версии.", 11 | "npm binary to use for internal operations.": "npm файл для использования во внутренних операциях.", 12 | "For the full documentation, see the manual page for npx(1).": "Полная документация доступна в мануале npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Невозможно угадать команду из %s. Пожалуйста, используйте --package.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: Нужно указать команду.\n", 15 | "Command failed: %s %s": "Ошибка: %s %s", 16 | "Install for %s failed with code %s": "Установка %s завершилась с кодом ошибки %s", 17 | "%s not found. Trying with npx...": "%s не найдено. Пробуем с npx...", 18 | "command not found: %s": "команда не найдена: %s", 19 | "options": "опции", 20 | "command": "команда", 21 | "version": "версия", 22 | "command-arg": "аргумент", 23 | "command-string": "команда-строка", 24 | "shell": "shell", 25 | "package": "пакет", 26 | "npx: installed %s in %ss": "npx: установлен %s в %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Отключить вывод npx. Поведение подкоманд не будет изменено." 28 | } 29 | -------------------------------------------------------------------------------- /locales/sr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Izvršavam binarne pakete iz npm packages.\n%s", 3 | "Package to be installed.": "Paket će biti instaliran.", 4 | "Location of the npm cache.": "Lokacija npm keša.", 5 | "Skip installation if a package is missing.": "Preskoci instalaciju ako paket nedostaje.", 6 | "Path to user npmrc.": "Putanja do korisnikovog npmrc.", 7 | "Execute string as if inside `npm run-script`.": "Izvrši string kao da se nalazi unutar `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Skripta izvršava komandu sa, ako postoji.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Napravi kod u Terminalu koji će koristiti npx kao zamenu za \"komanda nije pronađena\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ignoriše postojeće binarne pakete u $PATH, ili u lokalnom projektu. Ovo će naterati npx da izvrši privremenu instalaciju i koristi najnoviju verziju.", 11 | "npm binary to use for internal operations.": "npm binarni paket za upotrebu u lokalnim operacijama.", 12 | "For the full documentation, see the manual page for npx(1).": "Za kompletnu dokumentaciju, pogledajte stranicu sa uputstvima za npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Ne možemo da pogodimo ime binarnog paketa iz %s. Molimo koristite --package.", 14 | "\nERROR: You must supply a command.\n": "\nERROR: Morate uneti komandu.\n", 15 | "Command failed: %s %s": "Komanda nije uspela: %s %s", 16 | "Install for %s failed with code %s": "Instalacija za %s nije uspela sa kodom %s", 17 | "%s not found. Trying with npx...": "%s nije pronadjen. Pokušavam sa npx...", 18 | "command not found: %s": "komanda nije pronadjena: %s", 19 | "options": "opcije", 20 | "command": "komanda", 21 | "version": "verzija", 22 | "command-arg": "command-arg", 23 | "command-string": "command-string", 24 | "shell": "shell", 25 | "package": "paket", 26 | "npx: installed %s in %ss": "npx: instaliran %s u %ss", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Zabranjen izlaz iz samog npx. Na podkomande neće biti uticaja..", 28 | "Extra node argument when calling a node binary.": "Dodatni node argument kada pozivate node binarni." 29 | } -------------------------------------------------------------------------------- /locales/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "npm paketlerinden program çalıştırın.\n%s", 3 | "Package to be installed.": "Yüklenecek paketin adı.", 4 | "Location of the npm cache.":"npm önbelleğinin yeri.", 5 | "Skip installation if a package is missing.": "Eğer eksik paket varsa yükleme adımını atla.", 6 | "Path to user npmrc.": "Kullanıcının npmrc dosyasının yeri.", 7 | "Execute string as if inside `npm run-script`.": "Komutu 'npm run-script' kapsamında çalıştır.", 8 | "Shell to execute the command with, if any.": "Komutların çalıştırılacağı shell.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Komut eğer 'command not found' hatası veriyorsa, komutu npx üzerinden bir daha dene.", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "$PATH ve lokal projede tanımlanmış programları pas geçer. Bu sayede, npx yeni bir yükleme yapar ve en son versiyonu kullanır.", 11 | "npm binary to use for internal operations.": "Bu programın çalıştırılmasında kullanılacak npm.", 12 | "For the full documentation, see the manual page for npx(1).": "Tamamını okumak için 'man npx'.", 13 | "Unable to guess a binary name from %s. Please use --package.": "%s için hangi npm paketi bilemedim. Lütfen --package kullanın.", 14 | "\nERROR: You must supply a command.\n": "\nHATA: Argüman vermelisiniz.\n", 15 | "Command failed: %s %s": "Komut çalıştırılamadı: %s %s", 16 | "Install for %s failed with code %s": "%s yüklenirken %s kodlu bir hata oluştu. Yükleme sonlandırıldı.", 17 | "%s not found. Trying with npx...": "%s bulunamadı. npx ile deniyorum...", 18 | "command not found": "komut bulunamadı", 19 | "options": "seçenekler", 20 | "command": "komut", 21 | "version": "versiyon", 22 | "command-arg": "argümanlar", 23 | "command-string": "argümanlar", 24 | "shell": "shell", 25 | "package": "paket", 26 | "npx": "npx", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "npx çıktısını durdur. Alt komutlar etkilenmez." 28 | } 29 | -------------------------------------------------------------------------------- /locales/uk.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "Виконуйте скрипти з npm пакетів.\n%s", 3 | "Package to be installed.": "Пакет, який буде встановлено.", 4 | "Location of the npm cache.": "Розташування npm кешу.", 5 | "Skip installation if a package is missing.": "Пропустити встановлення, якщо пакет відсутній.", 6 | "Path to user npmrc.": "Шлях до npmrc файлу користувача.", 7 | "Execute string as if inside `npm run-script`.": "Виконати рядок наче в `npm run-script`.", 8 | "Shell to execute the command with, if any.": "Shell для виконання команди, якщо є.", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "Генерує shell скрипт для використання npx як фолбеку для \"command not found\".", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "Ігнорує існуючі бінарники в $PATH, чи в локальному проекті. Це змусить npx виконати тимчасове встановлення з використанням останньої версії.", 11 | "npm binary to use for internal operations.": "npm файл для використання у внутрішніх операціях.", 12 | "For the full documentation, see the manual page for npx(1).": "Повну документацію дивіться в мануалі npx(1).", 13 | "Unable to guess a binary name from %s. Please use --package.": "Неможливо визначити ім'я бінарника з %s. Будь ласка, використовуйте --package.", 14 | "\nERROR: You must supply a command.\n": "\nПОМИЛКА: Ви повинні вказати команду.\n", 15 | "Command failed: %s %s": "Невдала команда: %s %s", 16 | "Install for %s failed with code %s": "Невдале встановлення %s з кодом помилки %s", 17 | "%s not found. Trying with npx...": "%s не знайдено. Спробуємо з npx...", 18 | "command not found: %s": "команда не знайдена: %s", 19 | "options": "опції", 20 | "command": "команда", 21 | "version": "версія", 22 | "command-arg": "команда-аргумент", 23 | "command-string": "команда-рядок", 24 | "shell": "shell", 25 | "package": "пакет", 26 | "npx: installed %s in %ss": "npx: встановлено %s за %sс", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "Вимкнути вивід npx. Поведінка підкоманд не буде змінена.", 28 | "Extra node argument when calling a node binary.": "Додатковий node аргумент під час виклику node бібліотеки." 29 | } 30 | -------------------------------------------------------------------------------- /locales/zh_CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "从 npm 的可执行包执行命令\n%s", 3 | "Package to be installed.": "包安装的路径", 4 | "Location of the npm cache.": "npm 缓存路径", 5 | "Skip installation if a package is missing.": "如果有包缺失,跳过安装", 6 | "Path to user npmrc.": "当前用户的 npmrc 路径", 7 | "Execute string as if inside `npm run-script`.": "像执行 `npm run-script` 一样执行一个字符串", 8 | "Shell to execute the command with, if any.": "执行命令用到的解释器,可选", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "产生“找不到命令”的错误码", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "忽略 $PATH 或工程里已有的可执行文件,这会强制使 npx 临时安装一次,并且使用其最新的版本", 11 | "npm binary to use for internal operations.": "为了执行内部操作的 npm 可执行文件", 12 | "For the full documentation, see the manual page for npx(1).": "可以通过 npx(1) 的手册找到完整说明文档", 13 | "Unable to guess a binary name from %s. Please use --package.": "无法推测出可执行文件名的来源 %s,请使用 --package", 14 | "\nERROR: You must supply a command.\n": "\n错误:您必须提供一个命令\n", 15 | "Command failed: %s %s": "执行失败:%s %s", 16 | "Install for %s failed with code %s": "安装 %s 失败,错误代码:%s", 17 | "%s not found. Trying with npx...": "找不到 %s,请尝试使用 npx...", 18 | "command not found: %s": "找不到命令:%s", 19 | "options": "选项", 20 | "command": "命令", 21 | "version": "版本", 22 | "command-arg": "命令的参数", 23 | "command-string": "命令的字符串", 24 | "shell": "命令行解释器", 25 | "package": "包", 26 | "npx: installed %s in %ss": "npx: %s 安装成功,用时 %s 秒", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "隐藏 npx 的输出,子命令不会受到影响", 28 | "Extra node argument when calling a node binary.": "调用 node 二进制时使用额外的 node 参数。" 29 | } 30 | -------------------------------------------------------------------------------- /locales/zh_TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "Execute binaries from npm packages.\n%s": "從 npm 套件的執行檔執行指令\n%s", 3 | "Package to be installed.": "套件安装的路徑", 4 | "Location of the npm cache.": "npm 快取路徑", 5 | "Skip installation if a package is missing.": "當套件遺失時,略過安裝", 6 | "Path to user npmrc.": "目前使用者的 npmrc 路徑", 7 | "Execute string as if inside `npm run-script`.": "以 `npm run-script` 的方式執行一個字串", 8 | "Shell to execute the command with, if any.": "執行指令所使用的殼層(Shell),選用", 9 | "Generate shell code to use npx as the \"command not found\" fallback.": "當 npx 找不到指令時,產生殼層(Shell)指令,並執行之", 10 | "Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.": "將會讓 npx 忽略 $PATH 環境變數或專案內已有的執行檔,並暫時安裝及使用最新版本的執行檔", 11 | "npm binary to use for internal operations.": "指定 npx 內部執行使用的 npm 執行檔", 12 | "For the full documentation, see the manual page for npx(1).": "參考 npx(1) 的文件以取得完整的說明", 13 | "Unable to guess a binary name from %s. Please use --package.": "無法從 %s 推測執行檔名稱,請使用 --package 參數", 14 | "\nERROR: You must supply a command.\n": "\n錯誤:您必須輸入一個指令\n", 15 | "Command failed: %s %s": "指令執行失敗:%s %s", 16 | "Install for %s failed with code %s": "安裝 %s 失敗,錯誤代碼:%s", 17 | "%s not found. Trying with npx...": "找不到 %s,請嘗試使用 npx...", 18 | "command not found: %s": "找不到指令:%s", 19 | "options": "選項", 20 | "command": "指令", 21 | "version": "版本", 22 | "command-arg": "指令的參數", 23 | "command-string": "指令字串", 24 | "shell": "殼層(Shell)", 25 | "package": "套件", 26 | "npx: installed %s in %ss": "npx: %s 安裝成功,花費 %s 秒", 27 | "Suppress output from npx itself. Subcommands will not be affected.": "隱藏 npx 的輸出,不影響子指令", 28 | "Extra node argument when calling a node binary.": "當呼叫 node 執行檔時,提供的額外參數" 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libnpx", 3 | "version": "10.2.0", 4 | "description": "support library for npx -- an tool for executing npm-based packages.", 5 | "main": "index.js", 6 | "man": "./libnpx.1", 7 | "files": [ 8 | "*.js", 9 | "libnpx.1", 10 | "locales" 11 | ], 12 | "scripts": { 13 | "bin": "make bin", 14 | "publish-bin": "npm run bin && cd bin && npm publish", 15 | "docs": "tail -n +2 README.md | marked-man --manual 'User Commands' --version \"$npm_package_name@$npm_package_version\" > $npm_package_name.1", 16 | "prerelease": "npm t && npm run docs", 17 | "postrelease": "npm publish && git push --follow-tags", 18 | "pretest": "standard *.js test bin/*.js locales", 19 | "release": "standard-version -s", 20 | "test": "cross-env NPX_UPDATE_LOCALE_FILES=true LC_ALL=en nyc --all -- tap -J test/*.js", 21 | "update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", 22 | "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" 23 | }, 24 | "repository": "https://github.com/zkat/npx", 25 | "keywords": [ 26 | "npm", 27 | "npm exec", 28 | "shell", 29 | "scripts", 30 | "npm bin", 31 | "cli" 32 | ], 33 | "author": { 34 | "name": "Kat Marchán", 35 | "email": "kzm@sykosomatic.org", 36 | "twitter": "maybekatz" 37 | }, 38 | "license": "ISC", 39 | "dependencies": { 40 | "dotenv": "^5.0.1", 41 | "handlebars": "^4.1.1", 42 | "lodash": "^4.17.11", 43 | "npm-package-arg": "^6.1.0", 44 | "rimraf": "^2.6.3", 45 | "safe-buffer": "^5.1.2", 46 | "update-notifier": "^2.5.0", 47 | "which": "^1.3.1", 48 | "y18n": "^4.0.0", 49 | "yargs": "^11.1.0" 50 | }, 51 | "devDependencies": { 52 | "cross-env": "^5.2.0", 53 | "json": "^9.0.6", 54 | "marked-man": "^0.2.1", 55 | "mkdirp": "^0.5.1", 56 | "npm": "^6.9.0", 57 | "nyc": "^13.3.0", 58 | "require-inject": "^1.4.4", 59 | "standard": "^11.0.1", 60 | "standard-version": "^4.4.0", 61 | "tacks": "^1.3.0", 62 | "tap": "^12.6.0", 63 | "weallbehave": "^1.2.0", 64 | "weallcontribute": "^1.0.8" 65 | }, 66 | "config": { 67 | "nyc": { 68 | "exclude": [ 69 | "node_modules/**", 70 | "test/**" 71 | ] 72 | } 73 | }, 74 | "engines": { 75 | "node": ">=4" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /parse-args.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | let npa 4 | const path = require('path') 5 | 6 | module.exports = parseArgs 7 | function parseArgs (argv, defaultNpm) { 8 | argv = argv || process.argv 9 | if (argv.length > 2 && argv[2][0] !== '-') { 10 | // fast-path around arg parsing! Don't even need to load yargs here. 11 | return fastPathArgs(argv, defaultNpm) 12 | } 13 | 14 | npa = require('npm-package-arg') 15 | 16 | const parser = yargsParser(argv, defaultNpm) 17 | 18 | const opts = parser.getOptions() 19 | const bools = new Set(opts.boolean) 20 | 21 | let cmdIndex 22 | let hasDashDash 23 | for (let i = 2; i < argv.length; i++) { 24 | const opt = argv[i] 25 | if (opt === '--') { 26 | hasDashDash = true 27 | break 28 | } else if (opt === '--node-arg' || opt === '-n') { 29 | argv[i] = `${opt}=${argv[i + 1]}` 30 | argv.splice(i + 1, 1) 31 | } else if (opt[0] === '-') { 32 | if ( 33 | // --no-install needs to be special-cased because we're abusing 34 | // yargs a bit in order to get the --help text right. 35 | opt !== '--no-install' && 36 | !bools.has(opt.replace(/^--?(no-)?/i, '')) && 37 | opt.indexOf('=') === -1 38 | ) { 39 | i++ 40 | } 41 | } else { 42 | cmdIndex = i 43 | break 44 | } 45 | } 46 | if (cmdIndex) { 47 | const parsed = parser.parse(argv.slice(0, cmdIndex)) 48 | const parsedCmd = npa(argv[cmdIndex]) 49 | parsed.command = parsed.package && parsedCmd.type !== 'directory' 50 | ? argv[cmdIndex] 51 | : guessCmdName(parsedCmd) 52 | parsed.isLocal = parsedCmd.type === 'directory' 53 | parsed.cmdOpts = argv.slice(cmdIndex + 1) 54 | if (typeof parsed.package === 'string') { 55 | parsed.package = [parsed.package] 56 | } 57 | parsed.packageRequested = !!parsed.package 58 | parsed.cmdHadVersion = parsed.package || parsedCmd.type === 'directory' 59 | ? false 60 | : parsedCmd.name !== parsedCmd.raw 61 | const pkg = parsed.package || [argv[cmdIndex]] 62 | parsed.p = parsed.package = pkg.map(p => npa(p).toString()) 63 | return parsed 64 | } else { 65 | const parsed = parser.parse(argv) 66 | if (typeof parsed.package === 'string') { 67 | parsed.package = [parsed.package] 68 | } 69 | // -c *requires* -p, because the -c string should not be touched by npx 70 | if (parsed.call && parsed.package) { 71 | parsed.packageRequested = !!parsed.package 72 | parsed.cmdHadVersion = false 73 | const pkg = parsed.package 74 | parsed.p = parsed.package = pkg.map(p => npa(p).toString()) 75 | } else if (parsed.call && !parsed.package) { 76 | parsed.packageRequested = false 77 | parsed.cmdHadVersion = false 78 | parsed.p = parsed.package = [] 79 | } else if (hasDashDash) { 80 | const splitCmd = parsed._.slice(2) 81 | const parsedCmd = npa(splitCmd[0]) 82 | parsed.command = parsed.package 83 | ? splitCmd[0] 84 | : guessCmdName(parsedCmd) 85 | parsed.cmdOpts = splitCmd.slice(1) 86 | parsed.packageRequested = !!parsed.package 87 | parsed.cmdHadVersion = parsed.package 88 | ? false 89 | : parsedCmd.name !== parsedCmd.raw 90 | const pkg = parsed.package || [splitCmd[0]] 91 | parsed.p = parsed.package = pkg.map(p => npa(p).toString()) 92 | } 93 | return parsed 94 | } 95 | } 96 | 97 | function fastPathArgs (argv, defaultNpm) { 98 | let parsedCmd 99 | let pkg 100 | if (argv[2].match(/^[a-z0-9_-]+$/i)) { 101 | parsedCmd = { registry: true, name: argv[2], raw: argv[2] } 102 | pkg = [`${argv[2]}@latest`] 103 | } else { 104 | npa = require('npm-package-arg') 105 | parsedCmd = npa(argv[2]) 106 | if (parsedCmd.type === 'directory') { 107 | pkg = [] 108 | } else { 109 | pkg = [parsedCmd.toString()] 110 | } 111 | } 112 | return { 113 | command: guessCmdName(parsedCmd), 114 | cmdOpts: argv.slice(3), 115 | packageRequested: false, 116 | isLocal: parsedCmd.type === 'directory', 117 | cmdHadVersion: ( 118 | parsedCmd.name !== parsedCmd.raw && 119 | parsedCmd.type !== 'directory' 120 | ), 121 | package: pkg, 122 | p: pkg, 123 | shell: false, 124 | noYargs: true, 125 | npm: defaultNpm || 'npm' 126 | } 127 | } 128 | 129 | parseArgs.showHelp = () => require('yargs').showHelp() 130 | 131 | module.exports._guessCmdName = guessCmdName 132 | function guessCmdName (spec) { 133 | if (typeof spec === 'string') { 134 | if (!npa) { npa = require('npm-package-arg') } 135 | spec = npa(spec) 136 | } 137 | if (spec.scope) { 138 | return spec.name.slice(spec.scope.length + 1) 139 | } else if (spec.registry) { 140 | return spec.name 141 | } else if (spec.hosted && spec.hosted.project) { 142 | return spec.hosted.project 143 | } else if (spec.type === 'git') { 144 | const match = spec.fetchSpec.match(/([a-z0-9-]+)(?:\.git)?$/i) 145 | return match[1] 146 | } else if (spec.type === 'directory') { 147 | return spec.raw 148 | } else if (spec.type === 'file' || spec.type === 'remote') { 149 | let ext = path.extname(spec.fetchSpec) 150 | if (ext === '.gz') { 151 | ext = path.extname(path.basename(spec.fetchSpec, ext)) + ext 152 | } 153 | return path.basename(spec.fetchSpec, ext).replace(/-\d+\.\d+\.\d+(?:-[a-z0-9.\-+]+)?$/i, '') 154 | } 155 | 156 | console.error(Y()`Unable to guess a binary name from ${spec.raw}. Please use --package.`) 157 | return null 158 | } 159 | 160 | function yargsParser (argv, defaultNpm) { 161 | const usage = ` 162 | npx [${Y()`options`}] <${Y()`command`}>[@${Y()`version`}] [${Y()`command-arg`}]... 163 | 164 | npx [${Y()`options`}] [-p|--package <${Y()`package`}>]... <${Y()`command`}> [${Y()`command-arg`}]... 165 | 166 | npx [${Y()`options`}] -c '<${Y()`command-string`}>' 167 | 168 | npx --shell-auto-fallback [${Y()`shell`}] 169 | ` 170 | 171 | return require('yargs') 172 | .usage(Y()`Execute binaries from npm packages.\n${usage}`) 173 | .option('package', { 174 | alias: 'p', 175 | type: 'string', 176 | describe: Y()`Package to be installed.` 177 | }) 178 | .option('cache', { 179 | type: 'string', 180 | describe: Y()`Location of the npm cache.` 181 | }) 182 | .option('always-spawn', { 183 | describe: Y()`Always spawn a child process to execute the command.`, 184 | type: 'boolean' 185 | }) 186 | .option('no-install', { 187 | type: 'boolean', 188 | describe: Y()`Skip installation if a package is missing.` 189 | }) 190 | .option('userconfig', { 191 | type: 'string', 192 | describe: Y()`Path to user npmrc.` 193 | }) 194 | .option('call', { 195 | alias: 'c', 196 | type: 'string', 197 | describe: Y()`Execute string as if inside \`npm run-script\`.` 198 | }) 199 | .option('shell', { 200 | alias: 's', 201 | type: 'string', 202 | describe: Y()`Shell to execute the command with, if any.`, 203 | default: false 204 | }) 205 | .option('shell-auto-fallback', { 206 | choices: ['', 'bash', 'fish', 'zsh'], 207 | describe: Y()`Generate shell code to use npx as the "command not found" fallback.`, 208 | requireArg: false, 209 | type: 'string' 210 | }) 211 | .option('ignore-existing', { 212 | describe: Y()`Ignores existing binaries in $PATH, or in the local project. This forces npx to do a temporary install and use the latest version.`, 213 | type: 'boolean' 214 | }) 215 | .option('quiet', { 216 | alias: 'q', 217 | describe: Y()`Suppress output from npx itself. Subcommands will not be affected.`, 218 | type: 'boolean' 219 | }) 220 | .option('npm', { 221 | describe: Y()`npm binary to use for internal operations.`, 222 | type: 'string', 223 | default: defaultNpm || 'npm' 224 | }) 225 | .option('node-arg', { 226 | alias: 'n', 227 | type: 'string', 228 | describe: Y()`Extra node argument when calling a node binary.` 229 | }) 230 | .version() 231 | .alias('version', 'v') 232 | .help() 233 | .alias('help', 'h') 234 | .epilogue(Y()`For the full documentation, see the manual page for npx(1).`) 235 | } 236 | 237 | var _y 238 | function Y () { 239 | if (!_y) { _y = require('./y.js') } 240 | return _y 241 | } 242 | -------------------------------------------------------------------------------- /test/auto-fallback.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const child = require('../child.js') 4 | const exec = require('child_process').exec 5 | const path = require('path') 6 | const test = require('tap').test 7 | 8 | const NPX_BIN = child.escapeArg(path.join(__dirname, 'util', 'npx-bin.js')) 9 | 10 | test('not called with option', (t) => 11 | exec(`node ${NPX_BIN}`, (err, stdout, stderr) => { 12 | t.equal(err.code, 1) 13 | t.notOk(stdout) 14 | t.match(stderr, /--shell-auto-fallback/g) 15 | t.end() 16 | }) 17 | ) 18 | 19 | test('detect: SHELL ~= fish', (t) => 20 | exec(`node ${NPX_BIN} --shell-auto-fallback`, { 21 | env: { 22 | SHELL: '/usr/bin/fish' 23 | } 24 | }, (err, stdout, stderr) => { 25 | if (err) { throw err } 26 | t.match(stdout, /function __fish_command_not_found/) 27 | t.notOk(stderr) 28 | t.end() 29 | }) 30 | ) 31 | 32 | test('detect: SHELL ~= bash', (t) => 33 | exec(`node ${NPX_BIN} --shell-auto-fallback`, { 34 | env: { 35 | SHELL: '/bin/bash' 36 | } 37 | }, (err, stdout, stderr) => { 38 | if (err) { throw err } 39 | t.match(stdout, /command_not_found_handle\(/) 40 | t.notOk(stderr) 41 | t.end() 42 | }) 43 | ) 44 | 45 | test('detect: SHELL ~= zsh', (t) => 46 | exec(`node ${NPX_BIN} --shell-auto-fallback`, { 47 | env: { 48 | SHELL: '/usr/local/bin/zsh' 49 | } 50 | }, (err, stdout, stderr) => { 51 | if (err) { throw err } 52 | t.match(stdout, /command_not_found_handler\(/) 53 | t.notOk(stderr) 54 | t.end() 55 | }) 56 | ) 57 | 58 | test('detect: no SHELL', (t) => 59 | exec(`node ${NPX_BIN} --shell-auto-fallback`, { 60 | env: {} 61 | }, (err, stdout, stderr) => { 62 | t.equal(err.code, 1) 63 | t.notOk(stdout) 64 | t.match(stderr, /Only .+ shells are supported :\(/) 65 | t.end() 66 | }) 67 | ) 68 | 69 | test('detect: SHELL ~= unsupported', (t) => 70 | exec(`node ${NPX_BIN} --shell-auto-fallback`, { 71 | env: { 72 | SHELL: '/sbin/nope' 73 | } 74 | }, (err, stdout, stderr) => { 75 | t.equal(err.code, 1) 76 | t.notOk(stdout) 77 | t.match(stderr, /Only .+ shells are supported :\(/) 78 | t.end() 79 | }) 80 | ) 81 | 82 | test('given: fish', (t) => 83 | exec(`node ${NPX_BIN} --shell-auto-fallback fish`, (err, stdout, stderr) => { 84 | if (err) { throw err } 85 | t.match(stdout, /function __fish_command_not_found/) 86 | t.notOk(stderr) 87 | t.end() 88 | }) 89 | ) 90 | 91 | test('given: bash', (t) => 92 | exec(`node ${NPX_BIN} --shell-auto-fallback bash`, (err, stdout, stderr) => { 93 | if (err) { throw err } 94 | t.match(stdout, /command_not_found_handle\(/) 95 | t.notOk(stderr) 96 | t.end() 97 | }) 98 | ) 99 | 100 | test('given: zsh', (t) => 101 | exec(`node ${NPX_BIN} --shell-auto-fallback zsh`, (err, stdout, stderr) => { 102 | if (err) { throw err } 103 | t.match(stdout, /command_not_found_handler\(/) 104 | t.notOk(stderr) 105 | t.end() 106 | }) 107 | ) 108 | 109 | test('given: unsupported', (t) => 110 | exec(`node ${NPX_BIN} --shell-auto-fallback nope`, (err, stdout, stderr) => { 111 | t.equal(err.code, 1) 112 | t.notOk(stdout) 113 | t.match(stderr, /Invalid values:\s+Argument: shell-auto-fallback/) 114 | t.end() 115 | }) 116 | ) 117 | -------------------------------------------------------------------------------- /test/child.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const test = require('tap').test 4 | 5 | const child = require('../child.js') 6 | const requireInject = require('require-inject') 7 | 8 | test('escapeArg on *nix', t => { 9 | const origPlatform = process.platform 10 | Object.defineProperty(process, 'platform', {value: 'linux'}) 11 | t.equal(child.escapeArg('foo'), 'foo', 'standard arg left intact') 12 | t.equal(child.escapeArg('foo bar'), '\'foo bar\'', '\'-escaped on *nix') 13 | t.equal( 14 | child.escapeArg('/foo bar/baz\'quux.JPg', true), 15 | '\'/foo bar/baz\'"\'"\'quux.JPg\'', 16 | 'paths escaped as usual' 17 | ) 18 | Object.defineProperty(process, 'platform', {value: origPlatform}) 19 | t.done() 20 | }) 21 | 22 | test('escapeArg on win32', t => { 23 | const origPlatform = process.platform 24 | Object.defineProperty(process, 'platform', {value: 'win32'}) 25 | t.equal(child.escapeArg('foo'), '"foo"', 'standard arg escaped') 26 | t.equal(child.escapeArg('foo bar'), '"foo bar"', '"-escaped on win32') 27 | t.equal( 28 | child.escapeArg('C:\\Foo bar\\baz\'"\\quux.JPg', true), 29 | 'C:\\"Foo bar"\\baz\'"\\quux.JPg', 30 | 'paths escaped as usual' 31 | ) 32 | Object.defineProperty(process, 'platform', {value: origPlatform}) 33 | t.done() 34 | }) 35 | 36 | test('exec', t => { 37 | const child = requireInject('../child.js', { 38 | 'child_process': { 39 | exec (cmd, opts, cb) { 40 | if (opts.fail) { 41 | cb(new Error('exec failure requested')) 42 | } else { 43 | cb(null, {cmd, opts}) 44 | } 45 | } 46 | } 47 | }) 48 | const origPlatform = process.platform 49 | return child.exec('cmd', ['arg1', 'arg2'], {opt: 1}).then(ret => { 50 | t.equal(ret.cmd, 'cmd arg1 arg2', 'command string concatenated') 51 | t.deepEqual(ret.opts, {opt: 1}, 'options received!') 52 | Object.defineProperty(process, 'platform', {value: 'linux'}) 53 | return child.exec('/foo bar/baz .quux\\', ['arg1', 'arg 2']) 54 | }).then(ret => { 55 | t.equal(ret.cmd, "'/foo bar/baz .quux\\' arg1 arg 2", 'unix-style escapes') 56 | Object.defineProperty(process, 'platform', {value: 'win32'}) 57 | return child.exec('C:\\foo bar\\baz .quux\\a', ['arg1', 'arg 2']) 58 | }).then(ret => { 59 | t.equal(ret.cmd, 'C:\\"foo bar"\\"baz .quux"\\a arg1 arg 2', 'win32-style escapes') 60 | Object.defineProperty(process, 'platform', {value: origPlatform}) 61 | }).then(() => { 62 | return child.exec('fail', [], {fail: true}).then(() => { 63 | throw new Error('was supposed to fail') 64 | }, err => { 65 | t.equal(err.message, 'exec failure requested', 'got error') 66 | }) 67 | }) 68 | }) 69 | 70 | test('exec (integration)', t => { 71 | return child.exec('node', ['-p', '1+1']).then(stdout => { 72 | t.equal(stdout.trim(), '2', 'node ran successfully') 73 | return child.exec('node', ['-e', '"process.exit(123)"']).then(() => { 74 | throw new Error('was not supposed to succeed') 75 | }, err => { 76 | t.equal(err.exitCode, 123, 'got the exit code from subproc') 77 | }) 78 | }) 79 | }) 80 | 81 | test('spawn', t => { 82 | return child.spawn('node', ['-p', '1+1']).then(res => { 83 | t.deepEqual(res, { 84 | code: 0, 85 | stdout: '2\n', 86 | stderr: '' 87 | }) 88 | return child.spawn('node', ['-e', 'process.exit(123)']).then(() => { 89 | throw new Error('was not supposed to succeed') 90 | }, err => { 91 | t.equal(err.exitCode, 123, 'got the exit code from ') 92 | }) 93 | }) 94 | }) 95 | 96 | test('runCommand with command arg', t => { 97 | return child.runCommand('node', { 98 | cmdOpts: ['-p', '1+1'], 99 | stdio: 'pipe' 100 | }).then(res => { 101 | t.deepEqual(res, { 102 | code: 0, 103 | stdout: '2\n', 104 | stderr: '' 105 | }) 106 | return child.runCommand('node', { 107 | cmdOpts: ['-e', 'process.exit(123)'] 108 | }).then(() => { 109 | throw new Error('was not supposed to succeed') 110 | }, err => { 111 | t.equal(err.exitCode, 123, 'got the exit code from subproc') 112 | }) 113 | }).then(() => { 114 | return child.runCommand('./not-a-command-at-all', { 115 | stdio: 'pipe' 116 | }).then(() => { 117 | throw new Error('was not supposed to succeed') 118 | }, err => { 119 | if (process.platform === 'win32') { 120 | t.match(err.message, /Command failed/, 'error message reports failure') 121 | t.match(err.stderr, /not recognized as an internal or external command/, 'stderr reports command not found') 122 | } else { 123 | t.match(err.message, /command not found/, 'error message reports ENOENT') 124 | t.equal(err.exitCode, 127, '"not found" has code 127') 125 | } 126 | }) 127 | }) 128 | }) 129 | 130 | test('runCommand with opts.command', t => { 131 | return child.runCommand(null, { 132 | command: 'node', 133 | cmdOpts: ['-p', '1+1'], 134 | stdio: 'pipe' 135 | }).then(res => { 136 | t.deepEqual(res, { 137 | code: 0, 138 | stdout: '2\n', 139 | stderr: '' 140 | }) 141 | }) 142 | }) 143 | 144 | test('runCommand with opts.call and opts.shell', { 145 | skip: process.platform === 'win32' && 'Windows passes different flags to shell' 146 | }, t => { 147 | return child.runCommand(null, { 148 | shell: 'node', 149 | call: './child.js', 150 | stdio: 'pipe' 151 | }).then(res => { 152 | t.deepEqual(res, { 153 | code: 0, 154 | stdout: '', 155 | stderr: '' 156 | }) 157 | }) 158 | }) 159 | -------------------------------------------------------------------------------- /test/get-prefix.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const os = require('os') 4 | const path = require('path') 5 | const requireInject = require('require-inject') 6 | const Tacks = require('tacks') 7 | const test = require('tap').test 8 | const testDir = require('./util/test-dir.js')(__filename) 9 | 10 | const Dir = Tacks.Dir 11 | const File = Tacks.File 12 | 13 | const getPrefix = require('../get-prefix.js') 14 | 15 | test('navigates out of `node_modules` without fs nav', t => { 16 | return getPrefix( 17 | path.join(testDir, 'node_modules', 'node_modules') 18 | ).then(val => { 19 | t.equal(val, testDir, 'navigates out of node_modules') 20 | }) 21 | }) 22 | 23 | test('detects if currently in an npm package using package.json', t => { 24 | const fixture = new Tacks(Dir({ 25 | 'package.json': File({name: 'foo', version: '1.2.3'}) 26 | })) 27 | fixture.create(testDir) 28 | return getPrefix(testDir).then(prefix => { 29 | t.equal(prefix, testDir, 'current dir worked out') 30 | }) 31 | }) 32 | 33 | test('detects if currently in an npm package using node_modules', t => { 34 | const fixture = new Tacks(Dir({ 35 | 'node_modules': Dir({}) 36 | })) 37 | fixture.create(testDir) 38 | return getPrefix(testDir).then(prefix => { 39 | t.equal(prefix, testDir, 'current dir worked out') 40 | }) 41 | }) 42 | 43 | test('returns false if no package was found in parent dirs', t => { 44 | // Hopefully folks' tmpdir isn't inside an npm package ;) 45 | const tmp = os.tmpdir() 46 | return getPrefix(tmp).then(prefix => { 47 | t.equal(prefix, false, 'returned the false') 48 | }) 49 | }) 50 | 51 | test('navigates up the filesystem until it finds a package', t => { 52 | const fixture = new Tacks(Dir({ 53 | 'node_modules': Dir({}), 54 | 'a': Dir({'b': Dir({'c': Dir({'d': Dir({})})})}) 55 | })) 56 | fixture.create(testDir) 57 | return getPrefix(path.join(testDir, 'a', 'b', 'c')).then(prefix => { 58 | t.equal(prefix, testDir, 'navigated all the way up') 59 | }) 60 | }) 61 | 62 | test('doesn\'t go too far while navigating up', t => { 63 | const fixture = new Tacks(Dir({ 64 | 'node_modules': Dir({}), 65 | 'a': Dir({'node_modules': Dir({}), 'b': Dir({'c': Dir({'d': Dir({})})})}) 66 | })) 67 | fixture.create(testDir) 68 | return getPrefix(path.join(testDir, 'a', 'b', 'c')).then(prefix => { 69 | t.equal(prefix, path.join(testDir, 'a'), 'stopped before root') 70 | }) 71 | }) 72 | 73 | test('fileExists unit', t => { 74 | const fileExists = requireInject('../get-prefix.js', { 75 | fs: { 76 | stat (todo, cb) { 77 | if (todo === 'exists') { 78 | cb(null, {name: 'yay'}) 79 | } else if (todo === 'enoent') { 80 | const err = new Error('not found') 81 | err.code = 'ENOENT' 82 | cb(err) 83 | } else { 84 | cb(new Error('idk')) 85 | } 86 | } 87 | } 88 | })._fileExists 89 | return Promise.all([ 90 | fileExists('exists'), 91 | fileExists('enoent'), 92 | fileExists('kaboom').then(() => { 93 | throw new Error('nope') 94 | }, err => err) 95 | ]).then(results => { 96 | t.deepEqual(results[0], {name: 'yay'}, 'existing stat returned') 97 | t.notOk(results[1], 'missing file succeeds with falsy') 98 | t.match(results[2].message, /^idk$/, 'other errors thrown') 99 | }) 100 | }) 101 | 102 | test('isRootPath unit', t => { 103 | const isRoot = getPrefix._isRootPath 104 | t.ok(isRoot('C:\\', 'win32'), 'detected root on windows') 105 | t.notOk(isRoot('C:\\foo', 'win32'), 'detected non-root on windows') 106 | t.ok(isRoot('/', 'darwin'), 'detected root on darwin') 107 | t.notOk(isRoot('/foo', 'darwin'), 'detected non-root on darwin') 108 | t.ok(isRoot('/', 'linux'), 'detected root on linux') 109 | t.notOk(isRoot('/foo', 'linux'), 'detected non-root on linux') 110 | t.done() 111 | }) 112 | -------------------------------------------------------------------------------- /test/guess-command-name.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const test = require('tap').test 4 | 5 | const guessCmdName = require('../parse-args.js')._guessCmdName 6 | 7 | test('guesses unscoped registry binaries', t => { 8 | t.equal(guessCmdName('foo'), 'foo') 9 | t.done() 10 | }) 11 | 12 | test('guesses scoped registry binaries', t => { 13 | t.equal(guessCmdName('@user/foo'), 'foo') 14 | t.done() 15 | }) 16 | 17 | test('guesses hosted git binaries', t => { 18 | t.equal(guessCmdName('user/foo'), 'foo') 19 | t.equal(guessCmdName('git+ssh://git@github.com:user/foo.git#semver:^1'), 'foo') 20 | t.done() 21 | }) 22 | 23 | test('guesses git binaries', t => { 24 | t.equal(guessCmdName('git+ssh://myhost.com:user/foo.git#semver:^1'), 'foo') 25 | t.equal(guessCmdName('git://myhost.com:foo'), 'foo') 26 | t.done() 27 | }) 28 | 29 | test('leaves local directory/file commands intact', t => { 30 | t.equal(guessCmdName('./foo'), './foo') 31 | t.equal(guessCmdName('./dir/foo'), './dir/foo') 32 | t.equal(guessCmdName('../../../dir/foo'), '../../../dir/foo') 33 | t.equal( 34 | guessCmdName('C:\\Program Files\\node\\foo'), 35 | 'C:\\Program Files\\node\\foo' 36 | ) 37 | t.done() 38 | }) 39 | 40 | test('guesses remote tarballs', t => { 41 | t.equal(guessCmdName('https://registry.npmjs.org/foo/-/foo-1.2.3.tgz'), 'foo') 42 | t.equal(guessCmdName('http://registry.npmjs.org/foo/-/foo-1.2.3-prerelease.5+buildnum.tgz'), 'foo') 43 | t.equal(guessCmdName('https://github.com/tarball/blah/foo.tar.gz'), 'foo') 44 | t.done() 45 | }) 46 | 47 | test('guesses local tarballs', t => { 48 | t.equal(guessCmdName('./foo-1.2.3.tgz'), 'foo') 49 | t.equal(guessCmdName('./dir/foo.tar.gz'), 'foo') 50 | t.equal(guessCmdName('C:\\Program Files\\dir/foo-bar.tar.gz'), 'foo-bar') 51 | t.done() 52 | }) 53 | 54 | test('warns when something could not be guessed', t => { 55 | const oldErr = console.error 56 | console.error = str => { 57 | t.match(str, /Unable to guess a binary name/) 58 | } 59 | guessCmdName({}) 60 | console.error = oldErr 61 | t.done() 62 | }) 63 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Buffer = require('safe-buffer').Buffer 4 | 5 | const child = require('../child.js') 6 | const path = require('path') 7 | const requireInject = require('require-inject') 8 | const test = require('tap').test 9 | 10 | const main = require('../index.js') 11 | 12 | const isWindows = process.platform === 'win32' 13 | 14 | const NPX_PATH = path.resolve(__dirname, 'util', 'npx-bin.js') 15 | const NPM_PATH = path.resolve(__dirname, '..', 'node_modules', 'npm', 'bin', 'npm-cli.js') 16 | 17 | const NPX_ESC = isWindows ? child.escapeArg(NPX_PATH) : NPX_PATH 18 | 19 | test('npx --always-spawn', t => { 20 | return child.spawn('node', [ 21 | NPX_ESC, '--always-spawn', 'echo-cli', 'hewwo' 22 | ], {stdio: 'pipe'}).then(res => { 23 | t.equal(res.stdout.trim(), 'hewwo') 24 | }) 25 | }) 26 | 27 | test('npx --always-spawn resolves promise after command is executed', t => { 28 | const _runCommand = child.runCommand 29 | const parsed = main.parseArgs([ 30 | process.argv[0], 31 | '[fake arg]', 32 | '--always-spawn', 33 | 'echo-cli', 34 | 'hewwo' 35 | ], NPM_PATH) 36 | child.runCommand = (command, opts) => { 37 | child.runCommand = _runCommand 38 | return Promise.resolve([command, opts]) 39 | } 40 | return main(parsed) 41 | .then(args => { 42 | const command = args[0] 43 | const opts = args[1] 44 | t.ok(command.includes('node'), 'node executes the command') 45 | t.equal(opts.alwaysSpawn, true, 'set opts.alwaysSpawn') 46 | t.equal(opts.command, 'echo-cli', 'set opts.command') 47 | t.ok(opts.cmdOpts[0].includes('echo-cli'), 'set opts.cmdOpts[0]') 48 | t.equal(opts.cmdOpts[1], 'hewwo', 'set opts.cmdOpts[1]') 49 | }) 50 | }) 51 | 52 | test('npx --shell-auto-fallback', t => { 53 | return child.spawn('node', [ 54 | NPX_ESC, '--shell-auto-fallback', 'zsh' 55 | ], {stdio: 'pipe'}).then(res => { 56 | t.equal(res.code, 0, 'command succeeded') 57 | t.match( 58 | res.stdout, /command_not_found_handler\(\)/, 'got shell code in output' 59 | ) 60 | }) 61 | }) 62 | 63 | test('npx no command', t => { 64 | return child.spawn('node', [ 65 | NPX_ESC 66 | ], {stdio: 'pipe'}).then(res => { 67 | throw new Error('Should not have succeeded') 68 | }, err => { 69 | t.equal(err.exitCode, 1, 'got 1 as exit code') 70 | t.match( 71 | err.stderr, 72 | /ERROR: You must supply a command/, 73 | 'got a useful error message' 74 | ) 75 | t.match(err.stderr, /Execute binaries from npm/, 'npx help printed') 76 | }) 77 | }) 78 | 79 | test('npx existing subcommand', { 80 | skip: isWindows && 'Windows fail this test when run via nyc, but not when run directly' 81 | }, t => { 82 | return child.spawn('node', [ 83 | NPX_ESC, 'which', 'npm' 84 | ], {stdio: 'pipe'}).then(res => { 85 | t.notOk(res.stderr, 'no stderr output') 86 | t.ok(res.stdout.trim(), 'got output from command') 87 | }) 88 | }) 89 | 90 | test('execCommand unit', { 91 | skip: isWindows && 'need a workaround for obnoxious auto-open of .md file on Windows' 92 | }, t => { 93 | let whichBin = path.resolve( 94 | __dirname, '..', 'node_modules', '.bin', 'which' 95 | ) 96 | if (isWindows) { 97 | whichBin += '.CMD' 98 | } 99 | return main._execCommand(null, { 100 | command: path.resolve(__dirname, '..', 'README.md') 101 | }).then(res => { 102 | if (isWindows) { 103 | t.equal(res.code, 0, 'cmd.exe opened the file via its associated executable and returned success') 104 | } else { 105 | throw new Error('should not have succeeded') 106 | } 107 | }, err => { 108 | t.equal( 109 | typeof err.code, 'string', 'get a regular crash when the arg is invalid' 110 | ) 111 | }).then(() => { 112 | const oldCode = process.exitCode 113 | delete process.exitCode 114 | return main._execCommand(null, { 115 | stdio: 'pipe', 116 | command: whichBin 117 | }).then(() => { 118 | t.equal(process.exitCode, 1, 'set code without crashing, on cmd fail') 119 | process.exitCode = oldCode 120 | }) 121 | }) 122 | }) 123 | 124 | test('installPackages unit', t => { 125 | const installPkgs = requireInject('../index.js', { 126 | '../child.js': { 127 | spawn (npmPath, args) { 128 | if (args[2] === 'fail') { 129 | return Promise.reject(new Error('fail')) 130 | } else if (args[2] === 'codefail') { 131 | const err = new Error('npm failed') 132 | err.exitCode = 123 133 | return Promise.reject(err) 134 | } else if (args[2] === 'pathTest') { 135 | return Promise.resolve({ 136 | stdout: JSON.stringify(npmPath) 137 | }) 138 | } else { 139 | return Promise.resolve({ 140 | stdout: JSON.stringify([].slice.call(arguments)) 141 | }) 142 | } 143 | }, 144 | escapeArg (arg) { 145 | if (arg === '/f@ke_/path to/node') { 146 | return '\'/f@ke_/path to/node\'' 147 | } else if (arg === 'C:\\f@ke_\\path to\\node') { 148 | return '"C:\\f@ke_\\path to\\node"' 149 | } 150 | return arg 151 | } 152 | } 153 | })._installPackages 154 | return installPkgs(['installme@latest', 'file:foo'], 'myprefix', { 155 | npm: NPM_PATH 156 | }).then(deets => { 157 | t.deepEqual(deets[1], [ 158 | NPM_PATH, 159 | 'install', 'installme@latest', 'file:foo', 160 | '--global', 161 | '--prefix', 'myprefix', 162 | '--loglevel', 'error', 163 | '--json' 164 | ], 'args to spawn were correct for installing requested package') 165 | t.deepEqual(deets[2].stdio, [0, 'pipe', 2], 'default stdio settings correct') 166 | return installPkgs(['fail'], 'myprefix', { 167 | npm: NPM_PATH 168 | }).then(() => { 169 | throw new Error('should not have succeeded') 170 | }, err => { 171 | t.equal(err.message, 'fail', 'non-process failure reported intact') 172 | }) 173 | }).then(() => { 174 | return installPkgs(['codefail'], 'myprefix', { 175 | npm: NPM_PATH 176 | }).then(() => { 177 | throw new Error('should not have succeeded') 178 | }, err => { 179 | t.match( 180 | err.message, 181 | /Install for codefail failed with code 123/, 182 | 'npm install failure has helpful error message' 183 | ) 184 | t.equal(err.exitCode, 123, 'error has exitCode') 185 | }) 186 | }).then(() => { 187 | const nodePath = process.argv[0] 188 | process.argv[0] = isWindows ? 'C:\\f@ke_\\path to\\node' : '/f@ke_/path to/node' 189 | return installPkgs(['pathTest'], 'myprefix', { 190 | npm: NPM_PATH 191 | }).then((npmPath) => { 192 | process.argv[0] = nodePath 193 | if (isWindows) { 194 | t.equal(npmPath, '"C:\\f@ke_\\path to\\node"', 'incorrectly escaped path win32') 195 | } else { 196 | t.equal(npmPath, '/f@ke_/path to/node', 'incorrectly escaped path *nix') 197 | } 198 | }, (e) => { 199 | process.argv[0] = nodePath 200 | throw new Error('should not have failed') 201 | }) 202 | }) 203 | }) 204 | 205 | test('getEnv', t => { 206 | return main._getEnv({npm: NPM_PATH}).then(env => { 207 | t.ok(env, 'got the env') 208 | t.equal(env.npm_package_name, 'libnpx', 'env has run-script vars') 209 | }) 210 | }) 211 | 212 | test('getNpmCache', t => { 213 | const userconfig = 'blah' 214 | const getCache = requireInject('../index.js', { 215 | '../child.js': { 216 | exec (cmd, args) { 217 | return Promise.resolve(`${cmd} ${args.join(' ')}\n`) 218 | }, 219 | escapeArg (arg, asPath) { 220 | return `${arg}-escaped-as-path-${!!asPath}` 221 | } 222 | } 223 | })._getNpmCache 224 | return getCache({npm: NPM_PATH}).then(cache => { 225 | t.equal(cache, `${process.argv[0]} ${NPM_PATH}-escaped-as-path-false config get cache --parseable`, 'requests cache from npm') 226 | return getCache({npm: NPM_PATH, userconfig}) 227 | }).then(cache => { 228 | t.equal( 229 | cache, 230 | `${process.argv[0]} ${NPM_PATH}-escaped-as-path-false config get cache --parseable --userconfig ${ 231 | userconfig 232 | }-escaped-as-path-true`, 233 | 'added userconfig if option present' 234 | ) 235 | }) 236 | }) 237 | 238 | test('findNodeScript', t => { 239 | return main._findNodeScript(NPX_PATH).then(script => { 240 | if (isWindows) { 241 | t.notOk(script, 'win32 never detects Node scripts like this') 242 | } else { 243 | t.equal(script, NPX_PATH, 'existing returned as-is on *nix') 244 | } 245 | return main._findNodeScript(__filename).then(script => { 246 | t.notOk(script, 'files that are not standalone node scripts are false') 247 | }) 248 | }).then(() => { 249 | return main._findNodeScript(null).then(bool => { 250 | t.notOk(bool, 'no node script found if existing is null') 251 | }) 252 | }).then(() => { 253 | return main._findNodeScript(NPX_PATH, {isLocal: true}).then(script => { 254 | t.equal(script, NPX_PATH, 'resolved dir dep to index.js') 255 | }) 256 | }).then(() => { 257 | const findScript = requireInject('../index.js', { 258 | fs: { 259 | stat (file, cb) { 260 | cb(null, { 261 | isDirectory () { return !file.indexOf('./') } 262 | }) 263 | }, 264 | open (file, perm, cb) { 265 | cb(null, file) 266 | }, 267 | read (fd, buf, offset, length, position, cb) { 268 | if (fd === 'fail') { 269 | cb(new Error('fail')) 270 | } else { 271 | Buffer.from(fd).copy(buf) 272 | cb(null) 273 | } 274 | }, 275 | close (fd, cb) { 276 | cb() 277 | } 278 | } 279 | })._findNodeScript 280 | return findScript('fail').then(f => { 281 | if (isWindows) { 282 | t.notOk(f, 'win32 gives no fucks') 283 | } else { 284 | throw new Error('should have failed') 285 | } 286 | }, err => { 287 | t.equal(err.message, 'fail', 'close error rethrown') 288 | }) 289 | }) 290 | }) 291 | 292 | test('npx with custom installer stdio', t => { 293 | const NPX_PATH = path.resolve(__dirname, 'util', 'npx-bin-inherit-stdio.js') 294 | const NPX_ESC = isWindows ? child.escapeArg(NPX_PATH) : NPX_PATH 295 | 296 | return child.spawn('node', [ 297 | NPX_ESC, 'say-shalom@1.2.7' 298 | ], {stdio: 'pipe'}).then(res => { 299 | t.equal(res.code, 0, 'command succeeded') 300 | t.match( 301 | res.stdout.toString(), /"added":/, 'installer output printed directly to console' 302 | ) 303 | t.end() 304 | }) 305 | }) 306 | 307 | test('noisy npx with --quiet arg on windows', { 308 | skip: !isWindows && 'Only on Windows does the path to the downloaded module get printed' 309 | }, t => { 310 | return child.spawn('node', [ 311 | NPX_ESC, '--quiet', 'echo-cli', 'hewwo' 312 | ], {stdio: 'pipe'}).then(res => { 313 | t.equal(res.stdout.trim(), 'hewwo') 314 | t.end() 315 | }) 316 | }) 317 | 318 | test('nice error message when no binaries on windows', { 319 | skip: !isWindows && 'Only on Windows is the error message inscrutable' 320 | }, t => { 321 | return child.spawn('node', [ 322 | NPX_ESC, '0' 323 | ], {stdio: 'pipe'}).then(res => { 324 | throw new Error('Should not have succeeded') 325 | }, err => { 326 | t.equal(err.stderr.split('\n')[1].trim(), 'command not found: 0') 327 | t.end() 328 | }) 329 | }) 330 | 331 | test('--node-arg works on Windows', { 332 | skip: !isWindows && 'Only on Windows does --node-arg have issues' 333 | }, t => { 334 | return child.spawn('node', [ 335 | NPX_ESC, '--quiet', 336 | '--node-arg', '--no-deprecation', 337 | 'echo-cli', 'hewwo' 338 | ], {stdio: 'pipe'}).then(res => { 339 | t.equal(res.stdout.trim(), 'hewwo') 340 | t.end() 341 | }) 342 | }) 343 | -------------------------------------------------------------------------------- /test/parse-args.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const test = require('tap').test 4 | 5 | const parseArgs = require('../parse-args.js') 6 | 7 | function mockParse () { 8 | return parseArgs(['/node', '/npx'].concat([].slice.call(arguments))) 9 | } 10 | 11 | test('parses basic command', t => { 12 | const parsed = mockParse('foo') 13 | t.equal(parsed.command, 'foo') 14 | t.deepEqual(parsed.package, ['foo@latest']) 15 | t.equal(parsed.packageRequested, false) 16 | t.equal(parsed.cmdHadVersion, false) 17 | t.equal(parsed.npm, 'npm') 18 | t.deepEqual(parsed.cmdOpts, []) 19 | t.done() 20 | }) 21 | 22 | test('parses command with version', t => { 23 | const parsed = mockParse('foo@1.2.3') 24 | t.equal(parsed.command, 'foo') 25 | t.deepEqual(parsed.package, ['foo@1.2.3']) 26 | t.equal(parsed.packageRequested, false) 27 | t.equal(parsed.cmdHadVersion, true) 28 | t.done() 29 | }) 30 | 31 | test('parses command opts', t => { 32 | const parsed = mockParse('foo', 'a', 'b') 33 | t.equal(parsed.command, 'foo') 34 | t.deepEqual(parsed.package, ['foo@latest']) 35 | t.equal(parsed.packageRequested, false) 36 | t.equal(parsed.cmdHadVersion, false) 37 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 38 | t.done() 39 | }) 40 | 41 | test('parses scoped package command opts', t => { 42 | const parsed = mockParse('@user/foo', 'a', 'b') 43 | t.equal(parsed.command, 'foo') 44 | t.deepEqual(parsed.package, ['@user/foo@latest']) 45 | t.equal(parsed.packageRequested, false) 46 | t.equal(parsed.cmdHadVersion, false) 47 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 48 | t.done() 49 | }) 50 | 51 | test('ignores options after command', t => { 52 | const parsed = mockParse('foo', '-p', 'bar', 'a', 'b') 53 | t.equal(parsed.command, 'foo') 54 | t.deepEqual(parsed.package, ['foo@latest']) 55 | t.equal(parsed.packageRequested, false) 56 | t.equal(parsed.cmdHadVersion, false) 57 | t.deepEqual(parsed.cmdOpts, ['-p', 'bar', 'a', 'b']) 58 | t.done() 59 | }) 60 | 61 | test('assumes unknown args before cmd have values and ignores them', t => { 62 | const parsed = mockParse('-p', 'bar', '--blahh', 'arg', '--ignore-existing', 'foo', 'a', 'b') 63 | t.equal(parsed.command, 'foo') 64 | t.deepEqual(parsed.package, ['bar@latest']) 65 | t.equal(parsed.packageRequested, true) 66 | t.equal(parsed.cmdHadVersion, false) 67 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 68 | t.done() 69 | }) 70 | 71 | test('parses package option', t => { 72 | const parsed = mockParse('-p', 'bar', 'foo', 'a', 'b') 73 | t.equal(parsed.command, 'foo') 74 | t.deepEqual(parsed.package, ['bar@latest']) 75 | t.equal(parsed.packageRequested, true) 76 | t.equal(parsed.cmdHadVersion, false) 77 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 78 | t.done() 79 | }) 80 | 81 | test('parses multiple package options', t => { 82 | const parsed = mockParse('-p', 'baz@1.2.3', '-p', 'bar', 'foo', 'a', 'b') 83 | t.equal(parsed.command, 'foo') 84 | t.deepEqual(parsed.package, ['baz@1.2.3', 'bar@latest']) 85 | t.equal(parsed.packageRequested, true) 86 | t.equal(parsed.cmdHadVersion, false) 87 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 88 | t.done() 89 | }) 90 | 91 | test('does not parse -c', t => { 92 | const parsed = mockParse('-c', 'foo a b') 93 | t.deepEqual(parsed.command, null, 'stays unparsed') 94 | t.deepEqual(parsed.package, []) 95 | t.equal(parsed.packageRequested, false) 96 | t.equal(parsed.cmdHadVersion, false) 97 | t.deepEqual(parsed.cmdOpts, null) 98 | t.done() 99 | }) 100 | 101 | test('uses -p even with -c', t => { 102 | const parsed = mockParse('-c', 'foo a b', '-p', 'bar') 103 | t.deepEqual(parsed.command, null) 104 | t.deepEqual(parsed.package, ['bar@latest']) 105 | t.equal(parsed.packageRequested, true) 106 | t.equal(parsed.cmdHadVersion, false) 107 | t.deepEqual(parsed.cmdOpts, null) 108 | t.done() 109 | }) 110 | 111 | test('-p prevents command parsing', t => { 112 | const parsed = mockParse('-p', 'pkg', 'foo@1.2.3', 'a', 'b') 113 | t.equal(parsed.command, 'foo@1.2.3') 114 | t.deepEqual(parsed.package, ['pkg@latest']) 115 | t.equal(parsed.packageRequested, true) 116 | t.equal(parsed.cmdHadVersion, false) 117 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 118 | t.done() 119 | }) 120 | 121 | test('-- stops option parsing but still does command', t => { 122 | const parsed = mockParse('--', '-foo', 'a', 'b') 123 | t.equal(parsed.command, '-foo') 124 | t.deepEqual(parsed.package, ['-foo@latest']) 125 | t.equal(parsed.packageRequested, false) 126 | t.equal(parsed.cmdHadVersion, false) 127 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 128 | t.done() 129 | }) 130 | 131 | test('-- still respects -p', t => { 132 | const parsed = mockParse('-p', 'bar', '--', '-foo', 'a', 'b') 133 | t.equal(parsed.command, '-foo') 134 | t.deepEqual(parsed.package, ['bar@latest']) 135 | t.equal(parsed.packageRequested, true) 136 | t.equal(parsed.cmdHadVersion, false) 137 | t.deepEqual(parsed.cmdOpts, ['a', 'b']) 138 | t.done() 139 | }) 140 | 141 | test('allows configuration of npm binary', t => { 142 | const parsed = mockParse('--npm', './mynpm', 'foo') 143 | t.equal(parsed.npm, './mynpm') 144 | t.done() 145 | }) 146 | 147 | test('treats directory-type commands specially', t => { 148 | let parsed = mockParse('./foo') 149 | t.equal(parsed.command, './foo') 150 | t.deepEqual(parsed.package, []) 151 | t.equal(parsed.packageRequested, false) 152 | t.equal(parsed.cmdHadVersion, false) 153 | t.ok(parsed.isLocal) 154 | parsed = mockParse('-p', 'x', '../foo/bar.sh') 155 | t.equal(parsed.command, '../foo/bar.sh') 156 | t.ok(parsed.isLocal) 157 | t.deepEqual(parsed.package, ['x@latest']) 158 | t.equal(parsed.packageRequested, true) 159 | t.equal(parsed.cmdHadVersion, false) 160 | t.done() 161 | }) 162 | 163 | test('-n and --node-arg special parsing rules', t => { 164 | const command = 'command' 165 | t.like( 166 | mockParse('-n=--foo', command), 167 | {command, nodeArg: '--foo'} 168 | ) 169 | t.like( 170 | mockParse('-n', '--foo', command), 171 | {command, nodeArg: '--foo'} 172 | ) 173 | t.like( 174 | mockParse('--node-arg=--foo', command), 175 | {command, nodeArg: '--foo'} 176 | ) 177 | t.like( 178 | mockParse('--node-arg', '--foo', command), 179 | {command, nodeArg: '--foo'} 180 | ) 181 | t.like( 182 | mockParse('-n', '--foo', '-n', '--bar', '-n', 'baz', command), 183 | {command, nodeArg: ['--foo', '--bar', 'baz']} 184 | ) 185 | t.like( 186 | mockParse('--node-arg', '--foo', '--node-arg', '--bar', '--node-arg', 'baz', command), 187 | {command, nodeArg: ['--foo', '--bar', 'baz']} 188 | ) 189 | t.like( 190 | mockParse('-n', '--foo', '--node-arg', '--bar', '-n=baz', command), 191 | {command, nodeArg: ['--foo', '--bar', 'baz']} 192 | ) 193 | t.like( 194 | mockParse('-n', '-n', command), 195 | {command, nodeArg: '-n'} 196 | ) 197 | t.like( 198 | mockParse('--node-arg', '--node-arg', command), 199 | {command, nodeArg: '--node-arg'} 200 | ) 201 | t.like( 202 | mockParse(command, '--node-arg', 'blah'), 203 | {command, nodeArg: undefined, cmdOpts: ['--node-arg', 'blah']} 204 | ) 205 | t.done() 206 | }) 207 | -------------------------------------------------------------------------------- /test/util.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const test = require('tap').test 4 | 5 | test('promisify with existing util.promisify', t => { 6 | const promisify = require('../util.js').promisify 7 | const util = require('util') 8 | const origProm = util.promisify 9 | util.promisify = x => x 10 | t.equal(promisify('success'), 'success', 'used existing promisify fn') 11 | util.promisify = origProm 12 | t.done() 13 | }) 14 | 15 | test('promisify without existing util.promisify', t => { 16 | const promisify = require('../util.js').promisify 17 | const util = require('util') 18 | const origProm = util.promisify 19 | util.promisify = null 20 | const promisified = promisify((a, cb) => { 21 | if (a) { 22 | cb(null, a) 23 | } else { 24 | cb(new Error('fail')) 25 | } 26 | }) 27 | const p = promisified('yay') 28 | util.promisify = origProm 29 | t.ok(p.then, 'got a thenable') 30 | return p.then(val => { 31 | t.equal(val, 'yay', 'value passed through successfully') 32 | return promisified(false).then(() => { 33 | throw new Error('should have failed') 34 | }, err => { 35 | t.equal(err.message, 'fail', 'got the error!') 36 | }) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/util/npx-bin-inherit-stdio.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const npx = require('../../index.js') 4 | const path = require('path') 5 | 6 | const NPM_PATH = path.join(__dirname, '../..', 'node_modules', 'npm', 'bin', 'npm-cli.js') 7 | 8 | const npxOpts = Object.assign({}, npx.parseArgs(process.argv, NPM_PATH), { 9 | installerStdio: 'inherit' 10 | }) 11 | npx(npxOpts) 12 | -------------------------------------------------------------------------------- /test/util/npx-bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const npx = require('../../index.js') 4 | const path = require('path') 5 | 6 | const NPM_PATH = path.join(__dirname, '../..', 'node_modules', 'npm', 'bin', 'npm-cli.js') 7 | 8 | npx(npx.parseArgs(process.argv, NPM_PATH)) 9 | -------------------------------------------------------------------------------- /test/util/test-dir.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const mkdirp = require('mkdirp') 4 | const path = require('path') 5 | const rimraf = require('rimraf') 6 | const tap = require('tap') 7 | 8 | const cacheDir = path.resolve(__dirname, '../cache') 9 | 10 | module.exports = testDir 11 | function testDir (filename) { 12 | const base = path.basename(filename, '.js') 13 | const dir = path.join(cacheDir, base) 14 | tap.beforeEach(cb => { 15 | reset(dir, err => { 16 | if (err) { throw err } 17 | cb() 18 | }) 19 | }) 20 | if (!process.env.KEEPCACHE) { 21 | tap.tearDown(() => { 22 | process.chdir(__dirname) 23 | // This is ok cause this is the last 24 | // thing to run in the process 25 | rimraf(dir, () => {}) 26 | }) 27 | } 28 | return dir 29 | } 30 | 31 | module.exports.reset = reset 32 | function reset (testDir, cb) { 33 | process.chdir(__dirname) 34 | rimraf(testDir, function (err) { 35 | if (err) { return cb(err) } 36 | mkdirp(testDir, function (err) { 37 | if (err) { return cb(err) } 38 | process.chdir(testDir) 39 | cb() 40 | }) 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /util.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports.promisify = promisify 4 | function promisify (f) { 5 | const util = require('util') 6 | if (util.promisify) { 7 | return util.promisify(f) 8 | } else { 9 | return function () { 10 | return new Promise((resolve, reject) => { 11 | f.apply(this, [].slice.call(arguments).concat((err, val) => { 12 | err ? reject(err) : resolve(val) 13 | })) 14 | }) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /y.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | const yargs = require('yargs') 5 | const y18n = require('y18n')({ 6 | directory: path.join(__dirname, 'locales'), 7 | locale: yargs.locale(), 8 | updateFiles: process.env.NPX_UPDATE_LOCALE_FILES === 'true' 9 | }) 10 | 11 | module.exports = yTag 12 | function yTag (parts) { 13 | let str = '' 14 | parts.forEach((part, i) => { 15 | str += part 16 | if (arguments.length > i + 1) { 17 | str += '%s' 18 | } 19 | }) 20 | return y18n.__.apply(null, [str].concat([].slice.call(arguments, 1))) 21 | } 22 | --------------------------------------------------------------------------------