diff --git a/AUTHORS b/AUTHORS index ff19da4cf80a6..0a9c02f8b7d2b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -746,3 +746,4 @@ fuhao.xu marsonya <16393876+marsonya@users.noreply.github.com> Jeff Griffiths Michael Garvin +Gar diff --git a/CHANGELOG.md b/CHANGELOG.md index 6688fb0f5bd47..90812c0f9f70e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,66 @@ +## v7.4.1 (2021-01-14) + +### BUG FIXES + +* [`23df96d33`](https://github.com/npm/cli/commit/23df96d3394ba0b69a37f416d7f0c26bb9354975) + [#2486](https://github.com/npm/cli/issues/2486) + npm link no longer deletes entire project when global prefix is a symlink + ([@nlf](https://github.com/nlf)) + +### DOCUMENTATION + +* [`7dd0dfc59`](https://github.com/npm/cli/commit/7dd0dfc59c861e7d3e30a86a8e6db10872fc6b44) + [#2459](https://github.com/npm/cli/issues/2459) + fix(docs): clean up `npm start` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`307b3bd9f`](https://github.com/npm/cli/commit/307b3bd9f90e96fcc8805a1d5ddec80787a3d3a7) + [#2460](https://github.com/npm/cli/issues/2460) + fix(docs): clean up `npm stop` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`23f01b739`](https://github.com/npm/cli/commit/23f01b739d7a01a7dc3672322e14eb76ff33d712) + [#2462](https://github.com/npm/cli/issues/2462) + fix(docs): clean up `npm test` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`4b43656fc`](https://github.com/npm/cli/commit/4b43656fc608783a29ccf8495dc305459abc5cc7) + [#2463](https://github.com/npm/cli/issues/2463) + fix(docs): clean up `npm prefix` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`1135539ba`](https://github.com/npm/cli/commit/1135539bac9f98bb1a5d5ed05227a8ecd19493d3) + [`a07bb8e69`](https://github.com/npm/cli/commit/a07bb8e692a85b55d51850534c09fa58224c2285) + [`9b55b798e`](https://github.com/npm/cli/commit/9b55b798ed8f2b9be7b3199a1bfc23b1cd89c4cd) + [`cd5eeaaa0`](https://github.com/npm/cli/commit/cd5eeaaa08eabb505b65747a428c3c59159663dc) + [`6df69ce10`](https://github.com/npm/cli/commit/6df69ce107912f8429665eb851825d2acebc8575) + [`dc6b2a8b0`](https://github.com/npm/cli/commit/dc6b2a8b032d118be3566ce0fa7c67c171c8d2cb) + [`a3c127446`](https://github.com/npm/cli/commit/a3c1274460e16d1edbdca6a0cee86ef313fdd961) + [#2464](https://github.com/npm/cli/issues/2464) + fix(docs): clean up `npm uninstall` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`cfdcf32fd`](https://github.com/npm/cli/commit/cfdcf32fd7628501712b8cad4a541c6b8e7b66bc) + [#2474](https://github.com/npm/cli/issues/2474) + fix(docs): clean up `npm unpublish` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`acd5b062a`](https://github.com/npm/cli/commit/acd5b062a811fcd98849df908ce26855823ca671) + [#2475](https://github.com/npm/cli/issues/2475) + fix(docs): update `package-lock.json` docs + ([@isaacs](https://github.com/isaacs)) +* [`b0b0edf6d`](https://github.com/npm/cli/commit/b0b0edf6de1678de7f4a000700c88daa5f7194ef) + [#2482](https://github.com/npm/cli/issues/2482) + fix(docs): clean up `npm token` docs + ([@wraithgar](https://github.com/wraithgar)) +* [`35559201a`](https://github.com/npm/cli/commit/35559201a4a0a5b111ce58d6824e5b4030eb4496) + [#2487](https://github.com/npm/cli/issues/2487) + fix(docs): clean up `npm search` docs + ([@wraithgar](https://github.com/wraithgar)) + +### DEPENDENCIES + +* [`ea8c02169`](https://github.com/npm/cli/commit/ea8c02169cfbf0484d67db7c0e7a6ec8aecb7210) + `@npmcli/arborist@2.0.5` +* [`fb6f2c313`](https://github.com/npm/cli/commit/fb6f2c313d1d9770cc7d02a3900c7945df3cb661) + `pacote@11.2.1` +* [`c549b7657`](https://github.com/npm/cli/commit/c549b76573b1835a63e1e5898e9c16860079d84e) + `make-fetch-happen@8.0.13` + ## v7.4.0 (2021-01-07) ### FEATURES diff --git a/docs/content/commands/npm-audit.md b/docs/content/commands/npm-audit.md index 2c0a8f58047ca..7ad950a6ba99e 100644 --- a/docs/content/commands/npm-audit.md +++ b/docs/content/commands/npm-audit.md @@ -190,5 +190,4 @@ $ npm audit --audit-level=moderate ### See Also * [npm install](/commands/npm-install) -* [package-locks](/configuring-npm/package-locks) * [config](/using-npm/config) diff --git a/docs/content/commands/npm-ci.md b/docs/content/commands/npm-ci.md index 0d874f4f27a50..925ba8de2e5b7 100644 --- a/docs/content/commands/npm-ci.md +++ b/docs/content/commands/npm-ci.md @@ -68,4 +68,4 @@ cache: ### See Also * [npm install](/commands/npm-install) -* [package-locks](/configuring-npm/package-locks) +* [package-lock.json](/configuring-npm/package-lock-json) diff --git a/docs/content/commands/npm-prefix.md b/docs/content/commands/npm-prefix.md index 6894cb5c9298c..9c33bb18901ef 100644 --- a/docs/content/commands/npm-prefix.md +++ b/docs/content/commands/npm-prefix.md @@ -12,13 +12,25 @@ npm prefix [-g] ### Description -Print the local prefix to standard out. This is the closest parent directory +Print the local prefix to standard output. This is the closest parent directory to contain a `package.json` file or `node_modules` directory, unless `-g` is also specified. If `-g` is specified, this will be the value of the global prefix. See [`npm config`](/commands/npm-config) for more detail. +### Example + +```bash +npm prefix +/usr/local/projects/foo +``` + +```bash +npm prefix -g +/usr/local +``` + ### See Also * [npm root](/commands/npm-root) diff --git a/docs/content/commands/npm-search.md b/docs/content/commands/npm-search.md index 991bfe9e131f2..33864d472d4a2 100644 --- a/docs/content/commands/npm-search.md +++ b/docs/content/commands/npm-search.md @@ -16,35 +16,42 @@ aliases: s, se, find Search the registry for packages matching the search terms. `npm search` performs a linear, incremental, lexically-ordered search through package -metadata for all files in the registry. If color is enabled, it will further -highlight the matches in the results. +metadata for all files in the registry. If your terminal has color +support, it will further highlight the matches in the results. This can +be disabled with the config item `color` -Additionally, using the `--searchopts` and `--searchexclude` options paired with -more search terms will respectively include and exclude further patterns. The -main difference between `--searchopts` and the standard search terms is that the -former does not highlight results in the output and can be used for more -fine-grained filtering. Additionally, both of these can be added to `.npmrc` for -default search filtering behavior. +Additionally, using the `--searchopts` and `--searchexclude` options +paired with more search terms will include and exclude further patterns. +The main difference between `--searchopts` and the standard search terms +is that the former does not highlight results in the output and you can +use them more fine-grained filtering. Additionally, you can add both of +these to your config to change default search filtering behavior. Search also allows targeting of maintainers in search results, by prefixing their npm username with `=`. -If a term starts with `/`, then it's interpreted as a regular expression and -supports standard JavaScript RegExp syntax. A trailing `/` will be ignored in -this case. (Note that many regular expression characters must be escaped or -quoted in most shells.) - -### A Note on caching +If a term starts with `/`, then it's interpreted as a regular expression +and supports standard JavaScript RegExp syntax. In this case search will +ignore a trailing `/` . (Note you must escape or quote many regular +expression characters in most shells.) ### Configuration +All of the following can be defined in a `.npmrc` file, or passed as +parameters to the cli prefixed with `--` (e.g. `--json`) + #### description * Default: true * Type: Boolean -Used as `--no-description`, disables search matching in package descriptions and -suppresses display of that field in results. +#### color + + * Default: true + * Type: Boolean + +Used as `--no-color`, disables color highlighting of matches in the +results. #### json @@ -66,9 +73,9 @@ Output search results as lines with tab-separated columns. * Type: Boolean Display full package descriptions and other long text across multiple -lines. When disabled (default) search results are truncated to fit -neatly on a single line. Modules with extremely long names will -fall on multiple lines. +lines. When disabled (which is the default) the output will +truncate search results to fit neatly on a single line. Modules with +extremely long names will fall on multiple lines. #### searchopts @@ -84,23 +91,37 @@ Space-separated options that are always passed to search. Space-separated options that limit the results from search. -#### searchstaleness - -* Default: 900 (15 minutes) -* Type: Number - -The age of the cache, in seconds, before another registry request is made. - #### registry * Default: https://registry.npmjs.org/ * Type: url -Search the specified registry for modules. If you have configured npm to point -to a different default registry, such as your internal private module -repository, `npm search` will default to that registry when searching. Pass a -different registry url such as the default above in order to override this -setting. +Search the specified registry for modules. If you have configured npm to +point to a different default registry (such as your internal private +module repository), `npm search` will also default to that registry when +searching. + +### A note on caching + +The npm cli caches search results with the same terms and options +locally in its cache. You can use the following to change how and when +the cli uses this cache. See [`npm cache`](/commands/npm-cache) for more +on how the cache works. + +#### prefer-online + +Forced staleness checks for cached searches, making the cli look for +updates immediately even for fresh search results. + +#### prefer-offline + +Bypasses staleness checks for cached. Missing data will still be +requested from the server. To force full offline mode, use `offline`. + +#### offline + +Forces full offline mode. Any searches not locally cached will result in +an error. ### See Also @@ -108,3 +129,5 @@ setting. * [npm config](/commands/npm-config) * [npmrc](/configuring-npm/npmrc) * [npm view](/commands/npm-view) +* [npm cache](/commands/npm-cache) +* https://npm.im/npm-registry-fetch diff --git a/docs/content/commands/npm-shrinkwrap.md b/docs/content/commands/npm-shrinkwrap.md index 05d5706b9f9f1..dce50b7843bc3 100644 --- a/docs/content/commands/npm-shrinkwrap.md +++ b/docs/content/commands/npm-shrinkwrap.md @@ -13,18 +13,18 @@ npm shrinkwrap ### Description This command repurposes `package-lock.json` into a publishable -`npm-shrinkwrap.json` or simply creates a new one. The file created and updated -by this command will then take precedence over any other existing or future -`package-lock.json` files. For a detailed explanation of the design and purpose -of package locks in npm, see [package-locks](/configuring-npm/package-locks). +`npm-shrinkwrap.json` or simply creates a new one. The file created and +updated by this command will then take precedence over any other existing +or future `package-lock.json` files. For a detailed explanation of the +design and purpose of package locks in npm, see +[package-lock-json](/configuring-npm/package-lock-json). ### See Also * [npm install](/commands/npm-install) * [npm run-script](/commands/npm-run-script) * [npm scripts](/using-npm/scripts) -* [package.js](/configuring-npm/package-json) -* [package-locks](/configuring-npm/package-locks) +* [package.json](/configuring-npm/package-json) * [package-lock.json](/configuring-npm/package-lock-json) -* [shrinkwrap.json](/configuring-npm/shrinkwrap-json) +* [npm-shrinkwrap.json](/configuring-npm/npm-shrinkwrap-json) * [npm ls](/commands/npm-ls) diff --git a/docs/content/commands/npm-start.md b/docs/content/commands/npm-start.md index 8083bf8b7818e..4791719b592f6 100644 --- a/docs/content/commands/npm-start.md +++ b/docs/content/commands/npm-start.md @@ -12,13 +12,39 @@ npm start [-- ] ### Description -This runs an arbitrary command specified in the package's `"start"` property of -its `"scripts"` object. If no `"start"` property is specified on the -`"scripts"` object, it will run `node server.js`. +This runs a predefined command specified in the `"start"` property of +a package's `"scripts"` object. + +If the `"scripts"` object does not define a `"start"` property, npm +will run `node server.js`. + +Note that this is different from the default node behavior of running +the file specified in a package's `"main"` attribute when evoking with +`node .` As of [`npm@2.0.0`](https://blog.npmjs.org/post/98131109725/npm-2-0-0), you can use custom arguments when executing scripts. Refer to [`npm run-script`](/commands/npm-run-script) for more details. +### Example + +```json +{ + "scripts": { + "start": "node foo.js" + } +} +``` + +```bash +npm start + +> npm@x.x.x start +> node foo.js + +(foo.js output would be here) + +``` + ### See Also * [npm run-script](/commands/npm-run-script) diff --git a/docs/content/commands/npm-stop.md b/docs/content/commands/npm-stop.md index 17156c97c4043..9e8f9be360fd9 100644 --- a/docs/content/commands/npm-stop.md +++ b/docs/content/commands/npm-stop.md @@ -12,7 +12,31 @@ npm stop [-- ] ### Description -This runs a package's "stop" script, if one was provided. +This runs a predefined command specified in the "stop" property of a +package's "scripts" object. + +Unlike with [npm start](/commands/npm-start), there is no default script +that will run if the `"stop"` property is not defined. + +### Example + +```json +{ + "scripts": { + "stop": "node bar.js" + } +} +``` + +```bash +npm stop + +> npm@x.x.x stop +> node bar.js + +(bar.js output would be here) + +``` ### See Also diff --git a/docs/content/commands/npm-test.md b/docs/content/commands/npm-test.md index b8f25d520c821..2cc6a2e38b0f1 100644 --- a/docs/content/commands/npm-test.md +++ b/docs/content/commands/npm-test.md @@ -14,7 +14,28 @@ aliases: t, tst ### Description -This runs a package's "test" script, if one was provided. +This runs a predefined command specified in the `"test"` property of +a package's `"scripts"` object. + +### Example + +```json +{ + "scripts": { + "test": "node test.js" + } +} +``` + +```bash +npm test +> npm@x.x.x test +> node test.js + +(test.js output would be here) +``` + + ### See Also diff --git a/docs/content/commands/npm-token.md b/docs/content/commands/npm-token.md index 3716a0990299b..652079453702e 100644 --- a/docs/content/commands/npm-token.md +++ b/docs/content/commands/npm-token.md @@ -16,8 +16,8 @@ description: Manage your authentication tokens This lets you list, create and revoke authentication tokens. * `npm token list`: - Shows a table of all active authentication tokens. You can request this as - JSON with `--json` or tab-separated values with `--parseable`. + Shows a table of all active authentication tokens. You can request + this as JSON with `--json` or tab-separated values with `--parseable`. ```bash +--------+---------+------------+----------+----------------+ @@ -40,10 +40,17 @@ This lets you list, create and revoke authentication tokens. ``` * `npm token create [--read-only] [--cidr=]`: - Create a new authentication token. It can be `--read-only` or accept a list of - [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) ranges to - limit use of this token to. This will prompt you for your password, and, if you have - two-factor authentication enabled, an otp. + Create a new authentication token. It can be `--read-only`, or accept + a list of + [CIDR](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) + ranges with which to limit use of this token. This will prompt you for + your password, and, if you have two-factor authentication enabled, an + otp. + + Currently, the cli can not generate automation tokens. Please refer to + the [docs + website](https://docs.npmjs.com/creating-and-viewing-access-tokens) + for more information on generating automation tokens. ```bash +----------------+--------------------------------------+ @@ -58,7 +65,9 @@ This lets you list, create and revoke authentication tokens. ``` * `npm token revoke `: - This removes an authentication token, making it immediately unusable. This can accept - both complete tokens (as you get back from `npm token create` and will - find in your `.npmrc`) and ids as seen in the `npm token list` output. - This will NOT accept the truncated token found in `npm token list` output. + Immediately removes an authentication token from the registry. You + will no longer be able to use it. This can accept both complete + tokens (such as those you get back from `npm token create`, and those + found in your `.npmrc`), and ids as seen in the parseable or json + output of `npm token list`. This will NOT accept the truncated token + found in the normal `npm token list` output. diff --git a/docs/content/commands/npm-uninstall.md b/docs/content/commands/npm-uninstall.md index fe3c871138c19..258431cbd9f94 100644 --- a/docs/content/commands/npm-uninstall.md +++ b/docs/content/commands/npm-uninstall.md @@ -7,7 +7,7 @@ description: Remove a package ### Synopsis ```bash -npm uninstall [<@scope>/][@]... [-S|--save|-D|--save-dev|-O|--save-optional|--no-save] +npm uninstall [<@scope>/][@]... [-S|--save|--no-save] aliases: remove, rm, r, un, unlink ``` @@ -17,40 +17,43 @@ aliases: remove, rm, r, un, unlink This uninstalls a package, completely removing everything npm installed on its behalf. -Example: +It also removes the package from the `dependencies`, `devDependencies`, +`optionalDependencies`, and `peerDependencies` objects in your +`package.json`. -```bash -npm uninstall sax -``` +Futher, if you have an `npm-shrinkwrap.json` or `package-lock.json`, npm +will update those files as well. -In global mode (ie, with `-g` or `--global` appended to the command), -it uninstalls the current package context as a global package. - -`npm uninstall` takes 3 exclusive, optional flags which save or update -the package version in your main package.json: +`--no-save` will tell npm not to remove the package from your +`package.json`, `npm-shrinkwrap.json`, or `package-lock.json` files. -* `-S, --save`: Package will be removed from your `dependencies`. +`--save` or `-S` will tell npm to remove the package from your +`package.json`, `npm-shrinkwrap.json`, and `package-lock.json` files. +This is the default, but you may need to use this if you have for +instance `save=false` in your `npmrc` file -* `-D, --save-dev`: Package will be removed from your `devDependencies`. +In global mode (ie, with `-g` or `--global` appended to the command), +it uninstalls the current package context as a global package. +`--no-save` is ignored in this case. -* `-O, --save-optional`: Package will be removed from your `optionalDependencies`. +Scope is optional and follows the usual rules for [`scope`](/using-npm/scope). -* `--no-save`: Package will not be removed from your `package.json` file. +### Examples -Further, if you have an `npm-shrinkwrap.json` then it will be updated as -well. +```bash +npm uninstall sax +``` -Scope is optional and follows the usual rules for [`scope`](/using-npm/scope). +`sax` will no longer be in your `package.json`, `npm-shrinkwrap.json`, or +`package-lock.json` files. -Examples: ```bash -npm uninstall sax --save -npm uninstall @myorg/privatepackage --save -npm uninstall node-tap --save-dev -npm uninstall dtrace-provider --save-optional npm uninstall lodash --no-save ``` +`lodash` will not be removed from your `package.json`, +`npm-shrinkwrap.json`, or `package-lock.json` files. + ### See Also * [npm prune](/commands/npm-prune) diff --git a/docs/content/commands/npm-unpublish.md b/docs/content/commands/npm-unpublish.md index b39a7c09eb6e4..e9d6e9045c6f9 100644 --- a/docs/content/commands/npm-unpublish.md +++ b/docs/content/commands/npm-unpublish.md @@ -6,6 +6,10 @@ description: Remove a package from the registry ### Synopsis +To learn more about how the npm registry treats unpublish, see our unpublish policies + #### Unpublishing a single version of a package ```bash @@ -20,22 +24,26 @@ npm unpublish [<@scope>/] --force ### Warning -Consider using the `deprecate` command instead, if your intent is to encourage users to upgrade, or if you no longer want to maintain a package. +Consider using the [`deprecate`](/commands/npm-deprecate) command instead, +if your intent is to encourage users to upgrade, or if you no longer +want to maintain a package. ### Description -This removes a package version from the registry, deleting its -entry and removing the tarball. - -If no version is specified, or if all versions are removed then -the root package entry is removed from the registry entirely. +This removes a package version from the registry, deleting its entry and +removing the tarball. -Even if a package version is unpublished, that specific name and -version combination can never be reused. In order to publish the -package again, a new version number must be used. If you unpublish the entire package, you may not publish any new versions of that package until 24 hours have passed. +The npm registry will return an error if you are not [logged +in](/commands/npm-login). -To learn more about how unpublish is treated on the npm registry, see our unpublish policies. +If you do not specify a version or if you remove all of a package's +versions then the registry will remove the root package entry entirely. +Even if you unpublish a package version, that specific name and version +combination can never be reused. In order to publish the package again, +you must use a new version number. If you unpublish the entire package, +you may not publish any new versions of that package until 24 hours have +passed. ### See Also @@ -44,3 +52,4 @@ To learn more about how unpublish is treated on the npm registry, see our +* Don't put "js" or "node" in the name. It's assumed that it's js, since + you're writing a package.json file, and you can specify the engine using + the "engines" field. (See below.) +* The name will probably be passed as an argument to require(), so it + should be something short, but also reasonably descriptive. +* You may want to check the npm registry to see if there's something by + that name already, before you get too attached to it. + A name can be optionally prefixed by a scope, e.g. `@myorg/mypackage`. See [`scope`](/using-npm/scope) for more detail. @@ -48,14 +53,15 @@ A name can be optionally prefixed by a scope, e.g. `@myorg/mypackage`. See ### version If you plan to publish your package, the *most* important things in your -package.json are the name and version fields as they will be required. The name -and version together form an identifier that is assumed to be completely unique. -Changes to the package should come along with changes to the version. If you don't -plan to publish your package, the name and version fields are optional. +package.json are the name and version fields as they will be required. The +name and version together form an identifier that is assumed to be +completely unique. Changes to the package should come along with changes +to the version. If you don't plan to publish your package, the name and +version fields are optional. Version must be parseable by -[node-semver](https://github.com/npm/node-semver), which is bundled -with npm as a dependency. (`npm install semver` to use it yourself.) +[node-semver](https://github.com/npm/node-semver), which is bundled with +npm as a dependency. (`npm install semver` to use it yourself.) More on version numbers and ranges at [semver](/using-npm/semver). @@ -66,8 +72,8 @@ package, as it's listed in `npm search`. ### keywords -Put keywords in it. It's an array of strings. This helps people -discover your package as it's listed in `npm search`. +Put keywords in it. It's an array of strings. This helps people discover +your package as it's listed in `npm search`. ### homepage @@ -82,71 +88,83 @@ Example: ### bugs The url to your project's issue tracker and / or the email address to which -issues should be reported. These are helpful for people who encounter issues -with your package. +issues should be reported. These are helpful for people who encounter +issues with your package. It should look like this: ```json -{ "url" : "https://github.com/owner/project/issues" -, "email" : "project@hostname.com" +{ + "url" : "https://github.com/owner/project/issues", + "email" : "project@hostname.com" } ``` -You can specify either one or both values. If you want to provide only a url, -you can specify the value for "bugs" as a simple string instead of an object. +You can specify either one or both values. If you want to provide only a +url, you can specify the value for "bugs" as a simple string instead of an +object. If a url is provided, it will be used by the `npm bugs` command. ### license -You should specify a license for your package so that people know how they are -permitted to use it, and any restrictions you're placing on it. +You should specify a license for your package so that people know how they +are permitted to use it, and any restrictions you're placing on it. -If you're using a common license such as BSD-2-Clause or MIT, add a -current SPDX license identifier for the license you're using, like this: +If you're using a common license such as BSD-2-Clause or MIT, add a current +SPDX license identifier for the license you're using, like this: ```json -{ "license" : "BSD-3-Clause" } +{ + "license" : "BSD-3-Clause" +} ``` -You can check [the full list of SPDX license IDs](https://spdx.org/licenses/). -Ideally you should pick one that is +You can check [the full list of SPDX license +IDs](https://spdx.org/licenses/). Ideally you should pick one that is [OSI](https://opensource.org/licenses/alphabetical) approved. -If your package is licensed under multiple common licenses, use an [SPDX license -expression syntax version 2.0 string](https://www.npmjs.com/package/spdx), like this: +If your package is licensed under multiple common licenses, use an [SPDX +license expression syntax version 2.0 +string](https://www.npmjs.com/package/spdx), like this: ```json -{ "license" : "(ISC OR GPL-3.0)" } +{ + "license" : "(ISC OR GPL-3.0)" +} ``` If you are using a license that hasn't been assigned an SPDX identifier, or if you are using a custom license, use a string value like this one: ```json -{ "license" : "SEE LICENSE IN " } +{ + "license" : "SEE LICENSE IN " +} ``` Then include a file named `` at the top level of the package. -Some old packages used license objects or a "licenses" property containing an -array of license objects: +Some old packages used license objects or a "licenses" property containing +an array of license objects: ```json // Not valid metadata -{ "license" : - { "type" : "ISC" - , "url" : "https://opensource.org/licenses/ISC" +{ + "license" : { + "type" : "ISC", + "url" : "https://opensource.org/licenses/ISC" } } // Not valid metadata -{ "licenses" : - [ - { "type": "MIT" - , "url": "https://www.opensource.org/licenses/mit-license.php" - } - , { "type": "Apache-2.0" - , "url": "https://opensource.org/licenses/apache2.0.php" +{ + "licenses" : [ + { + "type": "MIT", + "url": "https://www.opensource.org/licenses/mit-license.php" + }, + { + "type": "Apache-2.0", + "url": "https://opensource.org/licenses/apache2.0.php" } ] } @@ -155,35 +173,49 @@ array of license objects: Those styles are now deprecated. Instead, use SPDX expressions, like this: ```json -{ "license": "ISC" } +{ + "license": "ISC" +} +``` -{ "license": "(MIT OR Apache-2.0)" } +```json +{ + "license": "(MIT OR Apache-2.0)" +} ``` Finally, if you do not wish to grant others the right to use a private or unpublished package under any terms: ```json -{ "license": "UNLICENSED" } +{ + "license": "UNLICENSED" +} ``` + Consider also setting `"private": true` to prevent accidental publication. ### people fields: author, contributors -The "author" is one person. "contributors" is an array of people. A "person" -is an object with a "name" field and optionally "url" and "email", like this: +The "author" is one person. "contributors" is an array of people. A +"person" is an object with a "name" field and optionally "url" and "email", +like this: ```json -{ "name" : "Barney Rubble" -, "email" : "b@rubble.com" -, "url" : "http://barnyrubble.tumblr.com/" +{ + "name" : "Barney Rubble", + "email" : "b@rubble.com", + "url" : "http://barnyrubble.tumblr.com/" } ``` -Or you can shorten that all into a single string, and npm will parse it for you: +Or you can shorten that all into a single string, and npm will parse it for +you: ```json -"Barney Rubble (http://barnyrubble.tumblr.com/)" +{ + "author": "Barney Rubble (http://barnyrubble.tumblr.com/)" +} ``` Both email and url are optional either way. @@ -193,58 +225,61 @@ npm also sets a top-level "maintainers" field with your npm user info. ### funding You can specify an object containing an URL that provides up-to-date -information about ways to help fund development of your package, or -a string URL, or an array of these: +information about ways to help fund development of your package, or a +string URL, or an array of these: - "funding": { +```json +{ + "funding": { + "type" : "individual", + "url" : "http://example.com/donate" + }, + + "funding": { + "type" : "patreon", + "url" : "https://www.patreon.com/my-account" + }, + + "funding": "http://example.com/donate", + + "funding": [ + { "type" : "individual", "url" : "http://example.com/donate" - } - - "funding": { + }, + "http://example.com/donateAlso", + { "type" : "patreon", "url" : "https://www.patreon.com/my-account" } - - "funding": "http://example.com/donate" - - "funding": [ - { - "type" : "individual", - "url" : "http://example.com/donate" - }, - "http://example.com/donateAlso", - { - "type" : "patreon", - "url" : "https://www.patreon.com/my-account" - } - ] - + ] +} +``` Users can use the `npm fund` subcommand to list the `funding` URLs of all -dependencies of their project, direct and indirect. A shortcut to visit each -funding url is also available when providing the project name such as: -`npm fund ` (when there are multiple URLs, the first one will be -visited) +dependencies of their project, direct and indirect. A shortcut to visit +each funding url is also available when providing the project name such as: +`npm fund ` (when there are multiple URLs, the first one will +be visited) ### files -The optional `files` field is an array of file patterns that describes -the entries to be included when your package is installed as a -dependency. File patterns follow a similar syntax to `.gitignore`, but -reversed: including a file, directory, or glob pattern (`*`, `**/*`, and such) -will make it so that file is included in the tarball when it's packed. Omitting -the field will make it default to `["*"]`, which means it will include all files. +The optional `files` field is an array of file patterns that describes the +entries to be included when your package is installed as a dependency. File +patterns follow a similar syntax to `.gitignore`, but reversed: including a +file, directory, or glob pattern (`*`, `**/*`, and such) will make it so +that file is included in the tarball when it's packed. Omitting the field +will make it default to `["*"]`, which means it will include all files. -Some special files and directories are also included or excluded regardless of -whether they exist in the `files` array (see below). +Some special files and directories are also included or excluded regardless +of whether they exist in the `files` array (see below). -You can also provide a `.npmignore` file in the root of your package or -in subdirectories, which will keep files from being included. At the -root of your package it will not override the "files" field, but in -subdirectories it will. The `.npmignore` file works just like a -`.gitignore`. If there is a `.gitignore` file, and `.npmignore` is -missing, `.gitignore`'s contents will be used instead. +You can also provide a `.npmignore` file in the root of your package or in +subdirectories, which will keep files from being included. At the root of +your package it will not override the "files" field, but in subdirectories +it will. The `.npmignore` file works just like a `.gitignore`. If there is +a `.gitignore` file, and `.npmignore` is missing, `.gitignore`'s contents +will be used instead. Files included with the "package.json#files" field _cannot_ be excluded through `.npmignore` or `.gitignore`. @@ -276,24 +311,28 @@ Conversely, some files are always ignored: * `node_modules` * `config.gypi` * `*.orig` -* `package-lock.json` (use shrinkwrap instead) +* `package-lock.json` (use + [`npm-shrinkwrap.json`](/configuring-npm/npm-shrinkwrap-json) if you wish + it to be published) ### main -The main field is a module ID that is the primary entry point to your program. -That is, if your package is named `foo`, and a user installs it, and then does -`require("foo")`, then your main module's exports object will be returned. +The main field is a module ID that is the primary entry point to your +program. That is, if your package is named `foo`, and a user installs it, +and then does `require("foo")`, then your main module's exports object will +be returned. -This should be a module ID relative to the root of your package folder. +This should be a module relative to the root of your package folder. -For most modules, it makes the most sense to have a main script and often not -much else. +For most modules, it makes the most sense to have a main script and often +not much else. ### browser If your module is meant to be used client-side the browser field should be used instead of the main field. This is helpful to hint users that it might -rely on primitives that aren't available in Node.js modules. (e.g. `window`) +rely on primitives that aren't available in Node.js modules. (e.g. +`window`) ### bin @@ -302,35 +341,45 @@ install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the "npm" executable.) To use this, supply a `bin` field in your package.json which is a map of -command name to local file name. On install, npm will symlink that file into -`prefix/bin` for global installs, or `./node_modules/.bin/` for local +command name to local file name. On install, npm will symlink that file +into `prefix/bin` for global installs, or `./node_modules/.bin/` for local installs. For example, myapp could have this: ```json -{ "bin" : { "myapp" : "./cli.js" } } +{ + "bin": { + "myapp": "./cli.js" + } +} ``` -So, when you install myapp, it'll create a symlink from the `cli.js` script to -`/usr/local/bin/myapp`. +So, when you install myapp, it'll create a symlink from the `cli.js` script +to `/usr/local/bin/myapp`. -If you have a single executable, and its name should be the name -of the package, then you can just supply it as a string. For example: +If you have a single executable, and its name should be the name of the +package, then you can just supply it as a string. For example: ```json -{ "name": "my-program" -, "version": "1.2.5" -, "bin": "./path/to/program" } +{ + "name": "my-program", + "version": "1.2.5", + "bin": "./path/to/program" +} ``` would be the same as this: ```json -{ "name": "my-program" -, "version": "1.2.5" -, "bin" : { "my-program" : "./path/to/program" } } +{ + "name": "my-program", + "version": "1.2.5", + "bin": { + "my-program": "./path/to/program" + } +} ``` Please make sure that your file(s) referenced in `bin` starts with @@ -339,93 +388,88 @@ executable! ### man -Specify either a single file or an array of filenames to put in place for the -`man` program to find. +Specify either a single file or an array of filenames to put in place for +the `man` program to find. If only a single file is provided, then it's installed such that it is the -result from `man `, regardless of its actual filename. For example: +result from `man `, regardless of its actual filename. For +example: ```json -{ "name" : "foo" -, "version" : "1.2.3" -, "description" : "A packaged foo fooer for fooing foos" -, "main" : "foo.js" -, "man" : "./man/doc.1" +{ + "name": "foo", + "version": "1.2.3", + "description": "A packaged foo fooer for fooing foos", + "main": "foo.js", + "man": "./man/doc.1" } ``` -would link the `./man/doc.1` file in such that it is the target for `man foo` +would link the `./man/doc.1` file in such that it is the target for `man +foo` If the filename doesn't start with the package name, then it's prefixed. So, this: ```json -{ "name" : "foo" -, "version" : "1.2.3" -, "description" : "A packaged foo fooer for fooing foos" -, "main" : "foo.js" -, "man" : [ "./man/foo.1", "./man/bar.1" ] +{ + "name": "foo", + "version": "1.2.3", + "description": "A packaged foo fooer for fooing foos", + "main": "foo.js", + "man": [ + "./man/foo.1", + "./man/bar.1" + ] } ``` will create files to do `man foo` and `man foo-bar`. Man files must end with a number, and optionally a `.gz` suffix if they are -compressed. The number dictates which man section the file is installed into. +compressed. The number dictates which man section the file is installed +into. ```json -{ "name" : "foo" -, "version" : "1.2.3" -, "description" : "A packaged foo fooer for fooing foos" -, "main" : "foo.js" -, "man" : [ "./man/foo.1", "./man/foo.2" ] +{ + "name": "foo", + "version": "1.2.3", + "description": "A packaged foo fooer for fooing foos", + "main": "foo.js", + "man": [ + "./man/foo.1", + "./man/foo.2" + ] } ``` + will create entries for `man foo` and `man 2 foo` ### directories -The CommonJS [Packages](http://wiki.commonjs.org/wiki/Packages/1.0) spec details a -few ways that you can indicate the structure of your package using a `directories` -object. If you look at [npm's package.json](https://registry.npmjs.org/npm/latest), -you'll see that it has directories for doc, lib, and man. +The CommonJS [Packages](http://wiki.commonjs.org/wiki/Packages/1.0) spec +details a few ways that you can indicate the structure of your package +using a `directories` object. If you look at [npm's +package.json](https://registry.npmjs.org/npm/latest), you'll see that it +has directories for doc, lib, and man. In the future, this information may be used in other creative ways. -#### directories.lib - -Tell people where the bulk of your library is. Nothing special is done -with the lib folder in any way, but it's useful meta info. - #### directories.bin If you specify a `bin` directory in `directories.bin`, all the files in that folder will be added. -Because of the way the `bin` directive works, specifying both a -`bin` path and setting `directories.bin` is an error. If you want to -specify individual files, use `bin`, and for all the files in an -existing `bin` directory, use `directories.bin`. +Because of the way the `bin` directive works, specifying both a `bin` path +and setting `directories.bin` is an error. If you want to specify +individual files, use `bin`, and for all the files in an existing `bin` +directory, use `directories.bin`. #### directories.man A folder that is full of man pages. Sugar to generate a "man" array by walking the folder. -#### directories.doc - -Put markdown files in here. Eventually, these will be displayed nicely, -maybe, someday. - -#### directories.example - -Put example scripts in here. Someday, it might be exposed in some clever way. - -#### directories.test - -Put your tests in here. It is currently not exposed, but it might be in the -future. - ### repository Specify the place where your code lives. This is helpful for people who @@ -435,72 +479,80 @@ command will be able to find you. Do it like this: ```json -"repository": { - "type" : "git", - "url" : "https://github.com/npm/cli.git" -} - -"repository": { - "type" : "svn", - "url" : "https://v8.googlecode.com/svn/trunk/" +{ + "repository": { + "type": "git", + "url": "https://github.com/npm/cli.git" + } } ``` -The URL should be a publicly available (perhaps read-only) url that can be handed -directly to a VCS program without any modification. It should not be a url to an -html project page that you put in your browser. It's for computers. +The URL should be a publicly available (perhaps read-only) url that can be +handed directly to a VCS program without any modification. It should not +be a url to an html project page that you put in your browser. It's for +computers. -For GitHub, GitHub gist, Bitbucket, or GitLab repositories you can use the same -shortcut syntax you use for `npm install`: +For GitHub, GitHub gist, Bitbucket, or GitLab repositories you can use the +same shortcut syntax you use for `npm install`: ```json -"repository": "npm/npm" +{ + "repository": "npm/npm", -"repository": "github:user/repo" + "repository": "github:user/repo", -"repository": "gist:11081aaa281" + "repository": "gist:11081aaa281", -"repository": "bitbucket:user/repo" + "repository": "bitbucket:user/repo", -"repository": "gitlab:user/repo" + "repository": "gitlab:user/repo" +} ``` -If the `package.json` for your package is not in the root directory (for example -if it is part of a monorepo), you can specify the directory in which it lives: +If the `package.json` for your package is not in the root directory (for +example if it is part of a monorepo), you can specify the directory in +which it lives: ```json -"repository": { - "type" : "git", - "url" : "https://github.com/facebook/react.git", - "directory": "packages/react-dom" +{ + "repository": { + "type": "git", + "url": "https://github.com/facebook/react.git", + "directory": "packages/react-dom" + } } ``` ### scripts -The "scripts" property is a dictionary containing script commands that are run -at various times in the lifecycle of your package. The key is the lifecycle -event, and the value is the command to run at that point. +The "scripts" property is a dictionary containing script commands that are +run at various times in the lifecycle of your package. The key is the +lifecycle event, and the value is the command to run at that point. -See [`scripts`](/using-npm/scripts) to find out more about writing package scripts. +See [`scripts`](/using-npm/scripts) to find out more about writing package +scripts. ### config -A "config" object can be used to set configuration parameters used in package -scripts that persist across upgrades. For instance, if a package had the -following: +A "config" object can be used to set configuration parameters used in +package scripts that persist across upgrades. For instance, if a package +had the following: ```json -{ "name" : "foo" -, "config" : { "port" : "8080" } } +{ + "name": "foo", + "config": { + "port": "8080" + } +} ``` and then had a "start" command that then referenced the `npm_package_config_port` environment variable, then the user could override that by doing `npm config set foo:port 8001`. -See [`config`](/using-npm/config) and [`scripts`](/using-npm/scripts) for more on package -configs. +See [`config`](/using-npm/config) and [`scripts`](/using-npm/scripts) for +more on package configs. ### dependencies @@ -509,17 +561,19 @@ version range. The version range is a string which has one or more space-separated descriptors. Dependencies can also be identified with a tarball or git URL. -**Please do not put test harnesses or transpilers in your -`dependencies` object.** See `devDependencies`, below. +**Please do not put test harnesses or transpilers or other "development" +time tools in your `dependencies` object.** See `devDependencies`, below. -See [semver](/using-npm/semver) for more details about specifying version ranges. +See [semver](/using-npm/semver) for more details about specifying version +ranges. * `version` Must match `version` exactly * `>version` Must be greater than `version` * `>=version` etc * `=1.0.2 <2.1.2" - , "baz" : ">1.0.2 <=2.3.4" - , "boo" : "2.0.1" - , "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0" - , "asd" : "http://asdf.com/asdf.tar.gz" - , "til" : "~1.2" - , "elf" : "~1.2.3" - , "two" : "2.x" - , "thr" : "3.3.x" - , "lat" : "latest" - , "dyl" : "file:../dyl" +{ + "dependencies": { + "foo": "1.0.0 - 2.9999.9999", + "bar": ">=1.0.2 <2.1.2", + "baz": ">1.0.2 <=2.3.4", + "boo": "2.0.1", + "qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0", + "asd": "http://asdf.com/asdf.tar.gz", + "til": "~1.2", + "elf": "~1.2.3", + "two": "2.x", + "thr": "3.3.x", + "lat": "latest", + "dyl": "file:../dyl" } } ``` @@ -573,8 +629,8 @@ Git urls are of the form: If `#` is provided, it will be used to clone exactly that commit. If the commit-ish has the format `#semver:`, `` can be any valid semver range or exact version, and npm will look for any tags -or refs matching that range in the remote repository, much as it would for a -registry dependency. If neither `#` or `#semver:` is +or refs matching that range in the remote repository, much as it would for +a registry dependency. If neither `#` or `#semver:` is specified, then `master` is used. Examples: @@ -606,9 +662,9 @@ included. For example: #### Local Paths -As of version 2.0.0 you can provide a path to a local directory that contains a -package. Local paths can be saved using `npm install -S` or -`npm install --save`, using any of these forms: +As of version 2.0.0 you can provide a path to a local directory that +contains a package. Local paths can be saved using `npm install -S` or `npm +install --save`, using any of these forms: ```bash ../foo/bar @@ -629,32 +685,32 @@ in which case they will be normalized to a relative path and added to your } ``` -This feature is helpful for local offline development and creating -tests that require npm installing where you don't want to hit an -external server, but should not be used when publishing packages -to the public registry. +This feature is helpful for local offline development and creating tests +that require npm installing where you don't want to hit an external server, +but should not be used when publishing packages to the public registry. ### devDependencies If someone is planning on downloading and using your module in their -program, then they probably don't want or need to download and build -the external test or documentation framework that you use. +program, then they probably don't want or need to download and build the +external test or documentation framework that you use. -In this case, it's best to map these additional items in a `devDependencies` -object. +In this case, it's best to map these additional items in a +`devDependencies` object. -These things will be installed when doing `npm link` or `npm install` -from the root of a package, and can be managed like any other npm -configuration param. See [`config`](/using-npm/config) for more on the topic. +These things will be installed when doing `npm link` or `npm install` from +the root of a package, and can be managed like any other npm configuration +param. See [`config`](/using-npm/config) for more on the topic. For build steps that are not platform-specific, such as compiling -CoffeeScript or other languages to JavaScript, use the `prepare` -script to do this, and make the required package a devDependency. +CoffeeScript or other languages to JavaScript, use the `prepare` script to +do this, and make the required package a devDependency. For example: ```json -{ "name": "ethopia-waza", +{ + "name": "ethopia-waza", "description": "a delightfully fruity coffee varietal", "version": "1.2.3", "devDependencies": { @@ -667,17 +723,18 @@ For example: } ``` -The `prepare` script will be run before publishing, so that users -can consume the functionality without requiring them to compile it -themselves. In dev mode (ie, locally running `npm install`), it'll -run this script as well, so that you can test it easily. +The `prepare` script will be run before publishing, so that users can +consume the functionality without requiring them to compile it themselves. +In dev mode (ie, locally running `npm install`), it'll run this script as +well, so that you can test it easily. ### peerDependencies In some cases, you want to express the compatibility of your package with a host tool or library, while not necessarily doing a `require` of this host. -This is usually referred to as a *plugin*. Notably, your module may be exposing -a specific interface, expected and specified by the host documentation. +This is usually referred to as a *plugin*. Notably, your module may be +exposing a specific interface, expected and specified by the host +documentation. For example: @@ -691,34 +748,38 @@ For example: } ``` -This ensures your package `tea-latte` can be installed *along* with the second -major version of the host package `tea` only. `npm install tea-latte` could -possibly yield the following dependency graph: +This ensures your package `tea-latte` can be installed *along* with the +second major version of the host package `tea` only. `npm install +tea-latte` could possibly yield the following dependency graph: ```bash ├── tea-latte@1.3.5 └── tea@2.2.0 ``` -**NOTE: npm versions 1 and 2 will automatically install `peerDependencies` if -they are not explicitly depended upon higher in the dependency tree. In the -next major version of npm (npm@3), this will no longer be the case. You will -receive a warning that the peerDependency is not installed instead.** The -behavior in npms 1 & 2 was frequently confusing and could easily put you into -dependency hell, a situation that npm is designed to avoid as much as possible. +In npm versions 3 through 6, `peerDependencies` were not automatically +installed, and would raise a warning if an invalid version of the peer +dependency was found in the tree. As of npm v7, peerDependencies _are_ +installed by default. -Trying to install another plugin with a conflicting requirement will cause an -error. For this reason, make sure your plugin requirement is as broad as -possible, and not to lock it down to specific patch versions. +Trying to install another plugin with a conflicting requirement may cause +an error if the tree cannot be resolved correctly. For this reason, make +sure your plugin requirement is as broad as possible, and not to lock it +down to specific patch versions. -Assuming the host complies with [semver](https://semver.org/), only changes in -the host package's major version will break your plugin. Thus, if you've worked -with every 1.x version of the host package, use `"^1.0"` or `"1.x"` to express -this. If you depend on features introduced in 1.5.2, use `">= 1.5.2 < 2"`. +Assuming the host complies with [semver](https://semver.org/), only changes +in the host package's major version will break your plugin. Thus, if you've +worked with every 1.x version of the host package, use `"^1.0"` or `"1.x"` +to express this. If you depend on features introduced in 1.5.2, use +`"^1.5.2"`. ### peerDependenciesMeta -When a user installs your package, npm will emit warnings if packages specified in `peerDependencies` are not already installed. The `peerDependenciesMeta` field serves to provide npm more information on how your peer dependencies are to be used. Specifically, it allows peer dependencies to be marked as optional. +When a user installs your package, npm will emit warnings if packages +specified in `peerDependencies` are not already installed. The +`peerDependenciesMeta` field serves to provide npm more information on how +your peer dependencies are to be used. Specifically, it allows peer +dependencies to be marked as optional. For example: @@ -738,7 +799,10 @@ For example: } ``` -Marking a peer dependency as optional ensures npm will not emit a warning if the `soy-milk` package is not installed on the host. This allows you to integrate and interact with a variety of host packages without requiring all of them to be installed. +Marking a peer dependency as optional ensures npm will not emit a warning +if the `soy-milk` package is not installed on the host. This allows you to +integrate and interact with a variety of host packages without requiring +all of them to be installed. ### bundledDependencies @@ -759,26 +823,28 @@ If we define a package.json like this: "name": "awesome-web-framework", "version": "1.0.0", "bundledDependencies": [ - "renderized", "super-streams" + "renderized", + "super-streams" ] } ``` + we can obtain `awesome-web-framework-1.0.0.tgz` file by running `npm pack`. This file contains the dependencies `renderized` and `super-streams` which can be installed in a new project by executing `npm install -awesome-web-framework-1.0.0.tgz`. Note that the package names do not include -any versions, as that information is specified in `dependencies`. +awesome-web-framework-1.0.0.tgz`. Note that the package names do not +include any versions, as that information is specified in `dependencies`. If this is spelled `"bundleDependencies"`, then that is also honored. ### optionalDependencies -If a dependency can be used, but you would like npm to proceed if it cannot be -found or fails to install, then you may put it in the `optionalDependencies` -object. This is a map of package name to version or url, just like the -`dependencies` object. The difference is that build failures do not cause -installation to fail. Running `npm install --no-optional` will prevent these -dependencies from being installed. +If a dependency can be used, but you would like npm to proceed if it cannot +be found or fails to install, then you may put it in the +`optionalDependencies` object. This is a map of package name to version or +url, just like the `dependencies` object. The difference is that build +failures do not cause installation to fail. Running `npm install +--no-optional` will prevent these dependencies from being installed. It is still your program's responsibility to handle the lack of the dependency. For example, something like this: @@ -809,32 +875,30 @@ Entries in `optionalDependencies` will override entries of the same name in You can specify the version of node that your stuff works on: ```json -{ "engines" : { "node" : ">=0.10.3 <0.12" } } +{ + "engines": { + "node": ">=0.10.3 <15" + } +} ``` And, like with dependencies, if you don't specify the version (or if you specify "\*" as the version), then any version of node will do. -If you specify an "engines" field, then npm will require that "node" be -somewhere on that list. If "engines" is omitted, then npm will just assume -that it works on node. - -You can also use the "engines" field to specify which versions of npm -are capable of properly installing your program. For example: +You can also use the "engines" field to specify which versions of npm are +capable of properly installing your program. For example: ```json -{ "engines" : { "npm" : "~1.0.20" } } +{ + "engines": { + "npm": "~1.0.20" + } +} ``` -Unless the user has set the `engine-strict` config flag, this -field is advisory only and will only produce warnings when your package is installed as a dependency. - -### engineStrict - -**This feature was removed in npm 3.0.0** - -Prior to npm 3.0.0, this feature was used to treat this package as if the -user had set `engine-strict`. It is no longer used. +Unless the user has set the `engine-strict` config flag, this field is +advisory only and will only produce warnings when your package is installed +as a dependency. ### os @@ -842,14 +906,23 @@ You can specify which operating systems your module will run on: ```json -"os" : [ "darwin", "linux" ] +{ + "os": [ + "darwin", + "linux" + ] +} ``` -You can also block instead of allowing operating systems, -just prepend the blocked os with a '!': +You can also block instead of allowing operating systems, just prepend the +blocked os with a '!': ```json -"os" : [ "!win32" ] +{ + "os": [ + "!win32" + ] +} ``` The host operating system is determined by `process.platform` @@ -863,62 +936,62 @@ If your code only runs on certain cpu architectures, you can specify which ones. ```json -"cpu" : [ "x64", "ia32" ] +{ + "cpu": [ + "x64", + "ia32" + ] +} ``` Like the `os` option, you can also block architectures: ```json -"cpu" : [ "!arm", "!mips" ] +{ + "cpu": [ + "!arm", + "!mips" + ] +} ``` The host architecture is determined by `process.arch` -### preferGlobal - -**DEPRECATED** - -This option used to trigger an npm warning, but it will no longer warn. It is -purely there for informational purposes. It is now recommended that you install -any binaries as local devDependencies wherever possible. - ### private -If you set `"private": true` in your package.json, then npm will refuse -to publish it. +If you set `"private": true` in your package.json, then npm will refuse to +publish it. -This is a way to prevent accidental publication of private repositories. If -you would like to ensure that a given package is only ever published to a -specific registry (for example, an internal registry), then use the -`publishConfig` dictionary described below to override the `registry` config -param at publish-time. +This is a way to prevent accidental publication of private repositories. +If you would like to ensure that a given package is only ever published to +a specific registry (for example, an internal registry), then use the +`publishConfig` dictionary described below to override the `registry` +config param at publish-time. ### publishConfig This is a set of config values that will be used at publish-time. It's especially handy if you want to set the tag, registry or access, so that you can ensure that a given package is not tagged with "latest", published -to the global public registry or that a scoped module is private by default. - -Any config values can be overridden, but only "tag", "registry" and "access" -probably matter for the purposes of publishing. +to the global public registry or that a scoped module is private by +default. -See [`config`](/using-npm/config) to see the list of config options that can be -overridden. +See [`config`](/using-npm/config) to see the list of config options that +can be overridden. ### workspaces The optional `workspaces` field is an array of file patterns that describes -locations within the local file system that the install client should look up -to find each [workspace](/using-npm/workspaces) that needs to be symlinked to -the top level `node_modules` folder. +locations within the local file system that the install client should look +up to find each [workspace](/using-npm/workspaces) that needs to be +symlinked to the top level `node_modules` folder. It can describe either the direct paths of the folders to be used as workspaces or it can define globs that will resolve to these same folders. -In the following example, all folders located inside the folder `./packages` -will be treated as workspaces as long as they have valid `package.json` files -inside them: +In the following example, all folders located inside the folder +`./packages` will be treated as workspaces as long as they have valid +`package.json` files inside them: ```json { @@ -937,20 +1010,20 @@ npm will default some values based on package contents. * `"scripts": {"start": "node server.js"}` - If there is a `server.js` file in the root of your package, then npm - will default the `start` command to `node server.js`. + If there is a `server.js` file in the root of your package, then npm will + default the `start` command to `node server.js`. * `"scripts":{"install": "node-gyp rebuild"}` - If there is a `binding.gyp` file in the root of your package and you have not defined an `install` or `preinstall` script, npm will - default the `install` command to compile using node-gyp. + If there is a `binding.gyp` file in the root of your package and you have + not defined an `install` or `preinstall` script, npm will default the + `install` command to compile using node-gyp. * `"contributors": [...]` - If there is an `AUTHORS` file in the root of your package, npm will - treat each line as a `Name (url)` format, where email and url - are optional. Lines which start with a `#` or are blank, will be - ignored. + If there is an `AUTHORS` file in the root of your package, npm will treat + each line as a `Name (url)` format, where email and url are + optional. Lines which start with a `#` or are blank, will be ignored. ### SEE ALSO diff --git a/docs/content/configuring-npm/package-lock-json.md b/docs/content/configuring-npm/package-lock-json.md index a3083410f7e2a..4d994bbc8c0a2 100644 --- a/docs/content/configuring-npm/package-lock-json.md +++ b/docs/content/configuring-npm/package-lock-json.md @@ -14,132 +14,223 @@ generate identical trees, regardless of intermediate dependency updates. This file is intended to be committed into source repositories, and serves various purposes: -* Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies. +* Describe a single representation of a dependency tree such that + teammates, deployments, and continuous integration are guaranteed to + install exactly the same dependencies. -* Provide a facility for users to "time-travel" to previous states of `node_modules` without having to commit the directory itself. +* Provide a facility for users to "time-travel" to previous states of + `node_modules` without having to commit the directory itself. -* To facilitate greater visibility of tree changes through readable source control diffs. +* Facilitate greater visibility of tree changes through readable source + control diffs. -* And optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages. +* Optimize the installation process by allowing npm to skip repeated + metadata resolutions for previously-installed packages. -One key detail about `package-lock.json` is that it cannot be published, and it -will be ignored if found in any place other than the toplevel package. It shares -a format with [npm-shrinkwrap.json](/configuring-npm/shrinkwrap-json), which is essentially the same file, but -allows publication. This is not recommended unless deploying a CLI tool or -otherwise using the publication process for producing production packages. +* As of npm v7, lockfiles include enough information to gain a complete + picture of the package tree, reducing the need to read `package.json` + files, and allowing for significant performance improvements. -If both `package-lock.json` and `npm-shrinkwrap.json` are present in the root of -a package, `package-lock.json` will be completely ignored. +### `package-lock.json` vs `npm-shrinkwrap.json` +Both of these files have the same format, and perform similar functions in +the root of a project. -### File Format +The difference is that `package-lock.json` is that it cannot be published, +and it will be ignored if found in any place other than the root project. -#### name +In contrast, [npm-shrinkwrap.json](/configuring-npm/npm-shrinkwrap-json) allows +publication, and defines the dependency tree from the point encountered. +This is not recommended unless deploying a CLI tool or otherwise using the +publication process for producing production packages. -The name of the package this is a package-lock for. This must match what's in -`package.json`. +If both `package-lock.json` and `npm-shrinkwrap.json` are present in the +root of a project, `npm-shrinkwrap.json` will take precedence and +`package-lock.json` will be ignored. -#### version +### Hidden Lockfiles -The version of the package this is a package-lock for. This must match what's in -`package.json`. +In order to avoid processing the `node_modules` folder repeatedly, npm as +of v7 uses a "hidden" lockfile present in +`node_modules/.package-lock.json`. This contains information about the +tree, and is used in lieu of reading the entire `node_modules` hierarchy +provided that the following conditions are met: -#### lockfileVersion +- All package folders it references exist in the `node_modules` hierarchy. +- No package folders exist in the `node_modules` hierarchy that are not + listed in the lockfile. +- The modified time of the file is at least as recent as all of the package + folders it references. -An integer version, starting at `1` with the version number of this document -whose semantics were used when generating this `package-lock.json`. +That is, the hidden lockfile will only be relevant if it was created as +part of the most recent update to the package tree. If another CLI mutates +the tree in any way, this will be detected, and the hidden lockfile will be +ignored. -#### packageIntegrity +Note that it _is_ possible to manually change the _contents_ of a package +in such a way that the modified time of the package folder is unaffected. +For example, if you add a file to `node_modules/foo/lib/bar.js`, then the +modified time on `node_modules/foo` will not reflect this change. If you +are manually editing files in `node_modules`, it is generally best to +delete the file at `node_modules/.package-lock.json`. -This is a [subresource -integrity](https://w3c.github.io/webappsec/specs/subresourceintegrity/) value -created from the `package.json`. No preprocessing of the `package.json` should -be done. Subresource integrity strings can be produced by modules like -[`ssri`](https://www.npmjs.com/package/ssri). +As the hidden lockfile is ignored by older npm versions, it does not +contain the backwards compatibility affordances present in "normal" +lockfiles. That is, it is `lockfileVersion: 3`, rather than +`lockfileVersion: 2`. -#### preserveSymlinks +### Handling Old Lockfiles -Indicates that the install was done with the environment variable -`NODE_PRESERVE_SYMLINKS` enabled. The installer should insist that the value of -this property match that environment variable. +When npm detects a lockfile from npm v6 or before during the package +installation process, it is automatically updated to fetch missing +information from either the `node_modules` tree or (in the case of empty +`node_modules` trees or very old lockfile formats) the npm registry. -#### dependencies +### File Format -A mapping of package name to dependency object. Dependency objects have the -following properties: +#### `name` -##### version +The name of the package this is a package-lock for. This will match what's +in `package.json`. -This is a specifier that uniquely identifies this package and should be -usable in fetching a new copy of it. +#### `version` -* bundled dependencies: Regardless of source, this is a version number that is purely for informational purposes. -* registry sources: This is a version number. (eg, `1.2.3`) -* git sources: This is a git specifier with resolved committish. (eg, `git+https://example.com/foo/bar#115311855adb0789a0466714ed48a1499ffea97e`) -* http tarball sources: This is the URL of the tarball. (eg, `https://example.com/example-1.3.0.tgz`) -* local tarball sources: This is the file URL of the tarball. (eg `file:///opt/storage/example-1.3.0.tgz`) -* local link sources: This is the file URL of the link. (eg `file:libs/our-module`) +The version of the package this is a package-lock for. This will match +what's in `package.json`. -##### integrity +#### `lockfileVersion` -This is a [Standard Subresource -Integrity](https://w3c.github.io/webappsec/specs/subresourceintegrity/) for this -resource. +An integer version, starting at `1` with the version number of this +document whose semantics were used when generating this +`package-lock.json`. -* For bundled dependencies this is not included, regardless of source. -* For registry sources, this is the `integrity` that the registry provided, or if one wasn't provided the SHA1 in `shasum`. -* For git sources this is the specific commit hash we cloned from. -* For remote tarball sources this is an integrity based on a SHA512 of - the file. -* For local tarball sources: This is an integrity field based on the SHA512 of the file. +Note that the file format changed significantly in npm v7 to track +information that would have otherwise required looking in `node_modules` or +the npm registry. Lockfiles generated by npm v7 will contain +`lockfileVersion: 2`. -##### resolved +* No version provided: an "ancient" shrinkwrap file from a version of npm + prior to npm v5. +* `1`: The lockfile version used by npm v5 and v6. +* `2`: The lockfile version used by npm v7, which is backwards compatible + to v1 lockfiles. +* `3`: The lockfile version used by npm v7, _without_ backwards + compatibility affordances. This is used for the hidden lockfile at + `node_modules/.package-lock.json`, and will likely be used in a future + version of npm, once support for npm v6 is no longer relevant. -* For bundled dependencies this is not included, regardless of source. -* For registry sources this is path of the tarball relative to the registry - URL. If the tarball URL isn't on the same server as the registry URL then - this is a complete URL. +npm will always attempt to get whatever data it can out of a lockfile, even +if it is not a version that it was designed to support. -##### bundled +#### `packages` -If true, this is the bundled dependency and will be installed by the parent -module. When installing, this module will be extracted from the parent -module during the extract phase, not installed as a separate dependency. +This is an object that maps package locations to an object containing the +information about that package. -##### dev +The root project is typically listed with a key of `""`, and all other +packages are listed with their relative paths from the root project folder. -If true then this dependency is either a development dependency ONLY of the -top level module or a transitive dependency of one. This is false for -dependencies that are both a development dependency of the top level and a -transitive dependency of a non-development dependency of the top level. +Package descriptors have the following fields: -##### optional +* version: The version found in `package.json` -If true then this dependency is either an optional dependency ONLY of the -top level module or a transitive dependency of one. This is false for -dependencies that are both an optional dependency of the top level and a -transitive dependency of a non-optional dependency of the top level. +* resolved: The place where the package was actually resolved from. In + the case of packages fetched from the registry, this will be a url to a + tarball. In the case of git dependencies, this will be the full git url + with commit sha. In the case of link dependencies, this will be the + location of the link target. -All optional dependencies should be included even if they're uninstallable -on the current platform. +* integrity: A `sha512` or `sha1` [Standard Subresource + Integrity](https://w3c.github.io/webappsec/specs/subresourceintegrity/) + string for the artifact that was unpacked in this location. +* link: A flag to indicate that this is a symbolic link. If this is + present, no other fields are specified, since the link target will also + be included in the lockfile. -##### requires +* dev, optional, devOptional: If the package is strictly part of the + `devDependencies` tree, then `dev` will be true. If it is strictly part + of the `optionalDependencies` tree, then `optional` will be set. If it + is both a `dev` dependency _and_ an `optional` dependency of a non-dev + dependency, then `devOptional` will be set. (An `optional` dependency of + a `dev` dependency will have both `dev` and `optional` set.) -This is a mapping of module name to version. This is a list of everything -this module requires, regardless of where it will be installed. The version -should match via normal matching rules a dependency either in our -`dependencies` or in a level higher than us. +* inBundle: A flag to indicate that the package is a bundled dependency. +* hasInstallScript: A flag to indicate that the package has a `preinstall`, + `install`, or `postinstall` script. -##### dependencies +* hasShrinkwrap: A flag to indicate that the package has an + `npm-shrinkwrap.json` file. + +* bin, license, engines, dependencies, optionalDependencies: fields from + `package.json` + +#### dependencies -The dependencies of this dependency, exactly as at the top level. +Legacy data for supporting versions of npm that use `lockfileVersion: 1`. +This is a mapping of package names to dependency objects. Because the +object structure is strictly hierarchical, symbolic link dependencies are +somewhat challenging to represent in some cases. + +npm v7 ignores this section entirely if a `packages` section is present, +but does keep it up to date in order to support switching between npm v6 +and npm v7. + +Dependency objects have the following fields: + +* version: a specifier that varies depending on the nature of the package, + and is usable in fetching a new copy of it. + + * bundled dependencies: Regardless of source, this is a version number + that is purely for informational purposes. + * registry sources: This is a version number. (eg, `1.2.3`) + * git sources: This is a git specifier with resolved committish. (eg, + `git+https://example.com/foo/bar#115311855adb0789a0466714ed48a1499ffea97e`) + * http tarball sources: This is the URL of the tarball. (eg, + `https://example.com/example-1.3.0.tgz`) + * local tarball sources: This is the file URL of the tarball. (eg + `file:///opt/storage/example-1.3.0.tgz`) + * local link sources: This is the file URL of the link. (eg + `file:libs/our-module`) + +* integrity: A `sha512` or `sha1` [Standard Subresource + Integrity](https://w3c.github.io/webappsec/specs/subresourceintegrity/) + string for the artifact that was unpacked in this location. For git + dependencies, this is the commit sha. + +* resolved: For registry sources this is path of the tarball relative to + the registry URL. If the tarball URL isn't on the same server as the + registry URL then this is a complete URL. + +* bundled: If true, this is the bundled dependency and will be installed + by the parent module. When installing, this module will be extracted + from the parent module during the extract phase, not installed as a + separate dependency. + +* dev: If true then this dependency is either a development dependency ONLY + of the top level module or a transitive dependency of one. This is false + for dependencies that are both a development dependency of the top level + and a transitive dependency of a non-development dependency of the top + level. + +* optional: If true then this dependency is either an optional dependency + ONLY of the top level module or a transitive dependency of one. This is + false for dependencies that are both an optional dependency of the top + level and a transitive dependency of a non-optional dependency of the top + level. + +* requires: This is a mapping of module name to version. This is a list of + everything this module requires, regardless of where it will be + installed. The version should match via normal matching rules a + dependency either in our `dependencies` or in a level higher than us. + +* dependencies: The dependencies of this dependency, exactly as at the top + level. ### See also * [npm shrinkwrap](/commands/npm-shrinkwrap) -* [shrinkwrap.json](/configuring-npm/shrinkwrap-json) -* [package-locks](/configuring-npm/package-locks) +* [npm-shrinkwrap.json](/configuring-npm/npm-shrinkwrap-json) * [package.json](/configuring-npm/package-json) * [npm install](/commands/npm-install) diff --git a/docs/content/configuring-npm/package-locks.md b/docs/content/configuring-npm/package-locks.md deleted file mode 100644 index a456ef8936645..0000000000000 --- a/docs/content/configuring-npm/package-locks.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -title: package-locks -section: 5 -description: An explanation of npm lockfiles ---- - -### Description - -Conceptually, the "input" to [`npm install`](/commands/npm-install) is a [package.json](/configuring-npm/package-json), while its -"output" is a fully-formed `node_modules` tree: a representation of the -dependencies you declared. In an ideal world, npm would work like a pure -function: the same `package.json` should produce the exact same `node_modules` -tree, any time. In some cases, this is indeed true. But in many others, npm is -unable to do this. There are multiple reasons for this: - -* different versions of npm (or other package managers) may have been used to install a package, each using slightly different installation algorithms. - -* a new version of a direct semver-range package may have been published since the last time your packages were installed, and thus a newer version will be used. - -* A dependency of one of your dependencies may have published a new version, which will update even if you used pinned dependency specifiers (`1.2.3` instead of `^1.2.3`) - -* The registry you installed from is no longer available, or allows mutation of versions (unlike the primary npm registry), and a different version of a package exists under the same version number now. - -As an example, consider package A: - -```json -{ - "name": "A", - "version": "0.1.0", - "dependencies": { - "B": "<0.1.0" - } -} -``` - -package B: - -```json -{ - "name": "B", - "version": "0.0.1", - "dependencies": { - "C": "<0.1.0" - } -} -``` - -and package C: -```json -{ - "name": "C", - "version": "0.0.1" -} -``` - -If these are the only versions of A, B, and C available in the -registry, then a normal `npm install A` will install: - -```json -A@0.1.0 -`-- B@0.0.1 - `-- C@0.0.1 -``` - -However, if B@0.0.2 is published, then a fresh `npm install A` will -install: - -```bash -A@0.1.0 -`-- B@0.0.2 - `-- C@0.0.1 -``` - -assuming the new version did not modify B's dependencies. Of course, -the new version of B could include a new version of C and any number -of new dependencies. If such changes are undesirable, the author of A -could specify a dependency on B@0.0.1. However, if A's author and B's -author are not the same person, there's no way for A's author to say -that he or she does not want to pull in newly published versions of C -when B hasn't changed at all. - -To prevent this potential issue, npm uses [package-lock.json](/configuring-npm/package-lock-json) or, if present, [npm-shrinkwrap.json](/configuring-npm/shrinkwrap-json). These files are called package locks, or lockfiles. - -Whenever you run `npm install`, npm generates or updates your package lock, -which will look something like this: - -```json -{ - "name": "A", - "version": "0.1.0", - ...metadata fields... - "dependencies": { - "B": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/B/-/B-0.0.1.tgz", - "integrity": "sha512-DeAdb33F+" - "dependencies": { - "C": { - "version": "git://github.com/org/C.git#5c380ae319fc4efe9e7f2d9c78b0faa588fd99b4" - } - } - } - } -} -``` - -This file describes an *exact*, and more importantly *reproducible* -`node_modules` tree. Once it's present, any future installation will base its -work off this file, instead of recalculating dependency versions off -[package.json](/configuring-npm/package-json). - -The presence of a package lock changes the installation behavior such that: - -1. The module tree described by the package lock is reproduced. This means -reproducing the structure described in the file, using the specific files -referenced in "resolved" if available, falling back to normal package resolution -using "version" if one isn't. - -2. The tree is walked and any missing dependencies are installed in the usual -fashion. - -If `preshrinkwrap`, `shrinkwrap` or `postshrinkwrap` are in the `scripts` -property of the `package.json`, they will be executed in order. `preshrinkwrap` -and `shrinkwrap` are executed before the shrinkwrap, `postshrinkwrap` is -executed afterwards. These scripts run for both `package-lock.json` and -`npm-shrinkwrap.json`. For example to run some postprocessing on the generated -file: - -```json - "scripts": { - "postshrinkwrap": "json -I -e \"this.myMetadata = $MY_APP_METADATA\"" - } -``` - -#### Using locked packages - -Using a locked package is no different than using any package without a package -lock: any commands that update `node_modules` and/or `package.json`'s -dependencies will automatically sync the existing lockfile. This includes `npm -install`, `npm rm`, `npm update`, etc. To prevent this update from happening, -you can use the `--no-save` option to prevent saving altogether, or -`--no-shrinkwrap` to allow `package.json` to be updated while leaving -`package-lock.json` or `npm-shrinkwrap.json` intact. - -It is highly recommended you commit the generated package lock to source -control: this will allow anyone else on your team, your deployments, your -CI/continuous integration, and anyone else who runs `npm install` in your -package source to get the exact same dependency tree that you were developing -on. Additionally, the diffs from these changes are human-readable and will -inform you of any changes npm has made to your `node_modules`, so you can notice -if any transitive dependencies were updated, hoisted, etc. - -#### Resolving lockfile conflicts - -Occasionally, two separate npm install will create package locks that cause -merge conflicts in source control systems. As of `npm@5.7.0`, these conflicts -can be resolved by manually fixing any `package.json` conflicts, and then -running `npm install [--package-lock-only]` again. npm will automatically -resolve any conflicts for you and write a merged package lock that includes all -the dependencies from both branches in a reasonable tree. If -`--package-lock-only` is provided, it will do this without also modifying your -local `node_modules/`. - -To make this process seamless on git, consider installing -[`npm-merge-driver`](https://npm.im/npm-merge-driver), which will teach git how -to do this itself without any user interaction. In short: `$ npx -npm-merge-driver install -g` will let you do this, and even works with -pre-`npm@5.7.0` versions of npm 5, albeit a bit more noisily. Note that if -`package.json` itself conflicts, you will have to resolve that by hand and run -`npm install` manually, even with the merge driver. - -### See Also - -* https://medium.com/@sdboyer/so-you-want-to-write-a-package-manager-4ae9c17d9527 -* [package.json](/configuring-npm/package-json) -* [package-lock.json](/configuring-npm/package-lock-json) -* [shrinkwrap.json](/configuring-npm/shrinkwrap-json) -* [npm shrinkwrap](/commands/npm-shrinkwrap) diff --git a/lib/link.js b/lib/link.js index f7e13369c86a2..84f36ada66201 100644 --- a/lib/link.js +++ b/lib/link.js @@ -45,6 +45,9 @@ const link = async args => { // Returns a list of items that can't be fulfilled by // things found in the current arborist inventory const missingArgsFromTree = (tree, args) => { + if (tree.isLink) + return missingArgsFromTree(tree.target, args) + const foundNodes = [] const missing = args.filter(a => { const arg = npa(a) diff --git a/lib/search.js b/lib/search.js index 38f5a1d77b322..a3d806d2f1507 100644 --- a/lib/search.js +++ b/lib/search.js @@ -12,7 +12,7 @@ const completion = require('./utils/completion/none.js') const usage = usageUtil( 'search', - 'npm search [--long] [search terms ...]' + 'npm search [-l|--long] [--json] [--parseable] [--no-description] [search terms ...]' ) const cmd = (args, cb) => search(args).then(() => cb()).catch(cb) diff --git a/lib/token.js b/lib/token.js index 98bbd30433cdd..b737b5ffbca32 100644 --- a/lib/token.js +++ b/lib/token.js @@ -17,7 +17,7 @@ token._validateCIDRList = validateCIDRList const usageUtil = require('./utils/usage.js') token.usage = usageUtil('token', 'npm token list\n' + - 'npm token revoke \n' + + 'npm token revoke \n' + 'npm token create [--read-only] [--cidr=list]') const UsageError = (msg) => diff --git a/lib/uninstall.js b/lib/uninstall.js index 83a0b009699eb..15995c0b3cc94 100644 --- a/lib/uninstall.js +++ b/lib/uninstall.js @@ -9,7 +9,7 @@ const completion = require('./utils/completion/installed-shallow.js') const usage = usageUtil( 'uninstall', - 'npm uninstall [<@scope>/][@]... [--save-prod|--save-dev|--save-optional] [--no-save]' + 'npm uninstall [<@scope>/][@]... [-S|--save|--no-save]' ) const cmd = (args, cb) => rm(args).then(() => cb()).catch(cb) diff --git a/lib/unpublish.js b/lib/unpublish.js index 75993af9437d0..528208c39693e 100644 --- a/lib/unpublish.js +++ b/lib/unpublish.js @@ -35,7 +35,7 @@ const completionFn = async (args) => { const access = await libaccess.lsPackages(username, opts) // do a bit of filtering at this point, so that we don't need // to fetch versions for more than one thing, but also don't - // accidentally a whole project + // accidentally unpublish a whole project let pkgs = Object.keys(access || {}) if (!partialWord || !pkgs.length) return pkgs diff --git a/node_modules/@npmcli/move-file/node_modules/.bin/rimraf b/node_modules/@npmcli/move-file/node_modules/.bin/rimraf new file mode 120000 index 0000000000000..4cd49a49ddfc1 --- /dev/null +++ b/node_modules/@npmcli/move-file/node_modules/.bin/rimraf @@ -0,0 +1 @@ +../rimraf/bin.js \ No newline at end of file diff --git a/node_modules/@npmcli/move-file/node_modules/rimraf/LICENSE b/node_modules/@npmcli/move-file/node_modules/rimraf/LICENSE new file mode 100644 index 0000000000000..19129e315fe59 --- /dev/null +++ b/node_modules/@npmcli/move-file/node_modules/rimraf/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/@npmcli/move-file/node_modules/rimraf/README.md b/node_modules/@npmcli/move-file/node_modules/rimraf/README.md new file mode 100644 index 0000000000000..423b8cf854ad3 --- /dev/null +++ b/node_modules/@npmcli/move-file/node_modules/rimraf/README.md @@ -0,0 +1,101 @@ +[![Build Status](https://travis-ci.org/isaacs/rimraf.svg?branch=master)](https://travis-ci.org/isaacs/rimraf) [![Dependency Status](https://david-dm.org/isaacs/rimraf.svg)](https://david-dm.org/isaacs/rimraf) [![devDependency Status](https://david-dm.org/isaacs/rimraf/dev-status.svg)](https://david-dm.org/isaacs/rimraf#info=devDependencies) + +The [UNIX command](http://en.wikipedia.org/wiki/Rm_(Unix)) `rm -rf` for node. + +Install with `npm install rimraf`, or just drop rimraf.js somewhere. + +## API + +`rimraf(f, [opts], callback)` + +The first parameter will be interpreted as a globbing pattern for files. If you +want to disable globbing you can do so with `opts.disableGlob` (defaults to +`false`). This might be handy, for instance, if you have filenames that contain +globbing wildcard characters. + +The callback will be called with an error if there is one. Certain +errors are handled for you: + +* Windows: `EBUSY` and `ENOTEMPTY` - rimraf will back off a maximum of + `opts.maxBusyTries` times before giving up, adding 100ms of wait + between each attempt. The default `maxBusyTries` is 3. +* `ENOENT` - If the file doesn't exist, rimraf will return + successfully, since your desired outcome is already the case. +* `EMFILE` - Since `readdir` requires opening a file descriptor, it's + possible to hit `EMFILE` if too many file descriptors are in use. + In the sync case, there's nothing to be done for this. But in the + async case, rimraf will gradually back off with timeouts up to + `opts.emfileWait` ms, which defaults to 1000. + +## options + +* unlink, chmod, stat, lstat, rmdir, readdir, + unlinkSync, chmodSync, statSync, lstatSync, rmdirSync, readdirSync + + In order to use a custom file system library, you can override + specific fs functions on the options object. + + If any of these functions are present on the options object, then + the supplied function will be used instead of the default fs + method. + + Sync methods are only relevant for `rimraf.sync()`, of course. + + For example: + + ```javascript + var myCustomFS = require('some-custom-fs') + + rimraf('some-thing', myCustomFS, callback) + ``` + +* maxBusyTries + + If an `EBUSY`, `ENOTEMPTY`, or `EPERM` error code is encountered + on Windows systems, then rimraf will retry with a linear backoff + wait of 100ms longer on each try. The default maxBusyTries is 3. + + Only relevant for async usage. + +* emfileWait + + If an `EMFILE` error is encountered, then rimraf will retry + repeatedly with a linear backoff of 1ms longer on each try, until + the timeout counter hits this max. The default limit is 1000. + + If you repeatedly encounter `EMFILE` errors, then consider using + [graceful-fs](http://npm.im/graceful-fs) in your program. + + Only relevant for async usage. + +* glob + + Set to `false` to disable [glob](http://npm.im/glob) pattern + matching. + + Set to an object to pass options to the glob module. The default + glob options are `{ nosort: true, silent: true }`. + + Glob version 6 is used in this module. + + Relevant for both sync and async usage. + +* disableGlob + + Set to any non-falsey value to disable globbing entirely. + (Equivalent to setting `glob: false`.) + +## rimraf.sync + +It can remove stuff synchronously, too. But that's not so good. Use +the async API. It's better. + +## CLI + +If installed with `npm install rimraf -g` it can be used as a global +command `rimraf [ ...]` which is useful for cross platform support. + +## mkdirp + +If you need to create a directory recursively, check out +[mkdirp](https://github.com/substack/node-mkdirp). diff --git a/node_modules/@npmcli/move-file/node_modules/rimraf/bin.js b/node_modules/@npmcli/move-file/node_modules/rimraf/bin.js new file mode 100755 index 0000000000000..0d1e17be701ec --- /dev/null +++ b/node_modules/@npmcli/move-file/node_modules/rimraf/bin.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node + +var rimraf = require('./') + +var help = false +var dashdash = false +var noglob = false +var args = process.argv.slice(2).filter(function(arg) { + if (dashdash) + return !!arg + else if (arg === '--') + dashdash = true + else if (arg === '--no-glob' || arg === '-G') + noglob = true + else if (arg === '--glob' || arg === '-g') + noglob = false + else if (arg.match(/^(-+|\/)(h(elp)?|\?)$/)) + help = true + else + return !!arg +}) + +if (help || args.length === 0) { + // If they didn't ask for help, then this is not a "success" + var log = help ? console.log : console.error + log('Usage: rimraf [ ...]') + log('') + log(' Deletes all files and folders at "path" recursively.') + log('') + log('Options:') + log('') + log(' -h, --help Display this usage info') + log(' -G, --no-glob Do not expand glob patterns in arguments') + log(' -g, --glob Expand glob patterns in arguments (default)') + process.exit(help ? 0 : 1) +} else + go(0) + +function go (n) { + if (n >= args.length) + return + var options = {} + if (noglob) + options = { glob: false } + rimraf(args[n], options, function (er) { + if (er) + throw er + go(n+1) + }) +} diff --git a/node_modules/@npmcli/move-file/node_modules/rimraf/package.json b/node_modules/@npmcli/move-file/node_modules/rimraf/package.json new file mode 100644 index 0000000000000..26e05d85ea2fd --- /dev/null +++ b/node_modules/@npmcli/move-file/node_modules/rimraf/package.json @@ -0,0 +1,29 @@ +{ + "name": "rimraf", + "version": "2.7.1", + "main": "rimraf.js", + "description": "A deep deletion module for node (like `rm -rf`)", + "author": "Isaac Z. Schlueter (http://blog.izs.me/)", + "license": "ISC", + "repository": "git://github.com/isaacs/rimraf.git", + "scripts": { + "preversion": "npm test", + "postversion": "npm publish", + "postpublish": "git push origin --all; git push origin --tags", + "test": "tap test/*.js" + }, + "bin": "./bin.js", + "dependencies": { + "glob": "^7.1.3" + }, + "files": [ + "LICENSE", + "README.md", + "bin.js", + "rimraf.js" + ], + "devDependencies": { + "mkdirp": "^0.5.1", + "tap": "^12.1.1" + } +} diff --git a/node_modules/@npmcli/move-file/node_modules/rimraf/rimraf.js b/node_modules/@npmcli/move-file/node_modules/rimraf/rimraf.js new file mode 100644 index 0000000000000..a90ad029f3ece --- /dev/null +++ b/node_modules/@npmcli/move-file/node_modules/rimraf/rimraf.js @@ -0,0 +1,372 @@ +module.exports = rimraf +rimraf.sync = rimrafSync + +var assert = require("assert") +var path = require("path") +var fs = require("fs") +var glob = undefined +try { + glob = require("glob") +} catch (_err) { + // treat glob as optional. +} +var _0666 = parseInt('666', 8) + +var defaultGlobOpts = { + nosort: true, + silent: true +} + +// for EMFILE handling +var timeout = 0 + +var isWindows = (process.platform === "win32") + +function defaults (options) { + var methods = [ + 'unlink', + 'chmod', + 'stat', + 'lstat', + 'rmdir', + 'readdir' + ] + methods.forEach(function(m) { + options[m] = options[m] || fs[m] + m = m + 'Sync' + options[m] = options[m] || fs[m] + }) + + options.maxBusyTries = options.maxBusyTries || 3 + options.emfileWait = options.emfileWait || 1000 + if (options.glob === false) { + options.disableGlob = true + } + if (options.disableGlob !== true && glob === undefined) { + throw Error('glob dependency not found, set `options.disableGlob = true` if intentional') + } + options.disableGlob = options.disableGlob || false + options.glob = options.glob || defaultGlobOpts +} + +function rimraf (p, options, cb) { + if (typeof options === 'function') { + cb = options + options = {} + } + + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert.equal(typeof cb, 'function', 'rimraf: callback function required') + assert(options, 'rimraf: invalid options argument provided') + assert.equal(typeof options, 'object', 'rimraf: options should be object') + + defaults(options) + + var busyTries = 0 + var errState = null + var n = 0 + + if (options.disableGlob || !glob.hasMagic(p)) + return afterGlob(null, [p]) + + options.lstat(p, function (er, stat) { + if (!er) + return afterGlob(null, [p]) + + glob(p, options.glob, afterGlob) + }) + + function next (er) { + errState = errState || er + if (--n === 0) + cb(errState) + } + + function afterGlob (er, results) { + if (er) + return cb(er) + + n = results.length + if (n === 0) + return cb() + + results.forEach(function (p) { + rimraf_(p, options, function CB (er) { + if (er) { + if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && + busyTries < options.maxBusyTries) { + busyTries ++ + var time = busyTries * 100 + // try again, with the same exact callback as this one. + return setTimeout(function () { + rimraf_(p, options, CB) + }, time) + } + + // this one won't happen if graceful-fs is used. + if (er.code === "EMFILE" && timeout < options.emfileWait) { + return setTimeout(function () { + rimraf_(p, options, CB) + }, timeout ++) + } + + // already gone + if (er.code === "ENOENT") er = null + } + + timeout = 0 + next(er) + }) + }) + } +} + +// Two possible strategies. +// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR +// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR +// +// Both result in an extra syscall when you guess wrong. However, there +// are likely far more normal files in the world than directories. This +// is based on the assumption that a the average number of files per +// directory is >= 1. +// +// If anyone ever complains about this, then I guess the strategy could +// be made configurable somehow. But until then, YAGNI. +function rimraf_ (p, options, cb) { + assert(p) + assert(options) + assert(typeof cb === 'function') + + // sunos lets the root user unlink directories, which is... weird. + // so we have to lstat here and make sure it's not a dir. + options.lstat(p, function (er, st) { + if (er && er.code === "ENOENT") + return cb(null) + + // Windows can EPERM on stat. Life is suffering. + if (er && er.code === "EPERM" && isWindows) + fixWinEPERM(p, options, er, cb) + + if (st && st.isDirectory()) + return rmdir(p, options, er, cb) + + options.unlink(p, function (er) { + if (er) { + if (er.code === "ENOENT") + return cb(null) + if (er.code === "EPERM") + return (isWindows) + ? fixWinEPERM(p, options, er, cb) + : rmdir(p, options, er, cb) + if (er.code === "EISDIR") + return rmdir(p, options, er, cb) + } + return cb(er) + }) + }) +} + +function fixWinEPERM (p, options, er, cb) { + assert(p) + assert(options) + assert(typeof cb === 'function') + if (er) + assert(er instanceof Error) + + options.chmod(p, _0666, function (er2) { + if (er2) + cb(er2.code === "ENOENT" ? null : er) + else + options.stat(p, function(er3, stats) { + if (er3) + cb(er3.code === "ENOENT" ? null : er) + else if (stats.isDirectory()) + rmdir(p, options, er, cb) + else + options.unlink(p, cb) + }) + }) +} + +function fixWinEPERMSync (p, options, er) { + assert(p) + assert(options) + if (er) + assert(er instanceof Error) + + try { + options.chmodSync(p, _0666) + } catch (er2) { + if (er2.code === "ENOENT") + return + else + throw er + } + + try { + var stats = options.statSync(p) + } catch (er3) { + if (er3.code === "ENOENT") + return + else + throw er + } + + if (stats.isDirectory()) + rmdirSync(p, options, er) + else + options.unlinkSync(p) +} + +function rmdir (p, options, originalEr, cb) { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) + assert(typeof cb === 'function') + + // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) + // if we guessed wrong, and it's not a directory, then + // raise the original error. + options.rmdir(p, function (er) { + if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) + rmkids(p, options, cb) + else if (er && er.code === "ENOTDIR") + cb(originalEr) + else + cb(er) + }) +} + +function rmkids(p, options, cb) { + assert(p) + assert(options) + assert(typeof cb === 'function') + + options.readdir(p, function (er, files) { + if (er) + return cb(er) + var n = files.length + if (n === 0) + return options.rmdir(p, cb) + var errState + files.forEach(function (f) { + rimraf(path.join(p, f), options, function (er) { + if (errState) + return + if (er) + return cb(errState = er) + if (--n === 0) + options.rmdir(p, cb) + }) + }) + }) +} + +// this looks simpler, and is strictly *faster*, but will +// tie up the JavaScript thread and fail on excessively +// deep directory trees. +function rimrafSync (p, options) { + options = options || {} + defaults(options) + + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert(options, 'rimraf: missing options') + assert.equal(typeof options, 'object', 'rimraf: options should be object') + + var results + + if (options.disableGlob || !glob.hasMagic(p)) { + results = [p] + } else { + try { + options.lstatSync(p) + results = [p] + } catch (er) { + results = glob.sync(p, options.glob) + } + } + + if (!results.length) + return + + for (var i = 0; i < results.length; i++) { + var p = results[i] + + try { + var st = options.lstatSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + + // Windows can EPERM on stat. Life is suffering. + if (er.code === "EPERM" && isWindows) + fixWinEPERMSync(p, options, er) + } + + try { + // sunos lets the root user unlink directories, which is... weird. + if (st && st.isDirectory()) + rmdirSync(p, options, null) + else + options.unlinkSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "EPERM") + return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) + if (er.code !== "EISDIR") + throw er + + rmdirSync(p, options, er) + } + } +} + +function rmdirSync (p, options, originalEr) { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) + + try { + options.rmdirSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "ENOTDIR") + throw originalEr + if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") + rmkidsSync(p, options) + } +} + +function rmkidsSync (p, options) { + assert(p) + assert(options) + options.readdirSync(p).forEach(function (f) { + rimrafSync(path.join(p, f), options) + }) + + // We only end up here once we got ENOTEMPTY at least once, and + // at this point, we are guaranteed to have removed all the kids. + // So, we know that it won't be ENOENT or ENOTDIR or anything else. + // try really hard to delete stuff on windows, because it has a + // PROFOUNDLY annoying habit of not closing handles promptly when + // files are deleted, resulting in spurious ENOTEMPTY errors. + var retries = isWindows ? 100 : 1 + var i = 0 + do { + var threw = true + try { + var ret = options.rmdirSync(p, options) + threw = false + return ret + } finally { + if (++i < retries && threw) + continue + } + } while (true) +} diff --git a/node_modules/make-fetch-happen/index.js b/node_modules/make-fetch-happen/index.js index b8d7bd98da596..54f72049c1d52 100644 --- a/node_modules/make-fetch-happen/index.js +++ b/node_modules/make-fetch-happen/index.js @@ -285,6 +285,10 @@ function remoteFetch (uri, opts) { size: opts.size, counter: opts.counter, timeout: opts.timeout, + ca: opts.ca, + cert: opts.cert, + key: opts.key, + rejectUnauthorized: opts.strictSSL, } return retry( diff --git a/node_modules/make-fetch-happen/package.json b/node_modules/make-fetch-happen/package.json index 4fc6163d5a027..2d555bcb86f41 100644 --- a/node_modules/make-fetch-happen/package.json +++ b/node_modules/make-fetch-happen/package.json @@ -1,6 +1,6 @@ { "name": "make-fetch-happen", - "version": "8.0.12", + "version": "8.0.13", "description": "Opinionated, caching, retrying fetch client", "main": "index.js", "files": [ diff --git a/node_modules/pacote/README.md b/node_modules/pacote/README.md index 81cd437efcd99..619e0ec44e8f6 100644 --- a/node_modules/pacote/README.md +++ b/node_modules/pacote/README.md @@ -162,6 +162,11 @@ resolved, and other properties, as they are determined. including information not strictly required for installation (author, description, etc.) Defaults to `true` when `before` is set, since the version publish time is part of the extended packument metadata. +* `packumentCache` For registry packuments only, you may provide a `Map` + object which will be used to cache packument requests between pacote + calls. This allows you to easily avoid hitting the registry multiple + times (even just to validate the cache) for a given packument, since it + is unlikely to change in the span of a single command. ## Extracted File Modes diff --git a/node_modules/pacote/lib/fetcher.js b/node_modules/pacote/lib/fetcher.js index 33fbf79c61b60..a0a1447a31dc4 100644 --- a/node_modules/pacote/lib/fetcher.js +++ b/node_modules/pacote/lib/fetcher.js @@ -60,6 +60,7 @@ class FetcherBase { // clone the opts object so that others aren't upset when we mutate it // by adding/modifying the integrity value. this.opts = {...opts} + this.cache = opts.cache || cacheDir() this.resolved = opts.resolved || null diff --git a/node_modules/pacote/lib/registry.js b/node_modules/pacote/lib/registry.js index b9df036146406..537610d2990d0 100644 --- a/node_modules/pacote/lib/registry.js +++ b/node_modules/pacote/lib/registry.js @@ -20,6 +20,14 @@ class RegistryFetcher extends Fetcher { constructor (spec, opts) { super(spec, opts) + // you usually don't want to fetch the same packument multiple times in + // the span of a given script or command, no matter how many pacote calls + // are made, so this lets us avoid doing that. It's only relevant for + // registry fetchers, because other types simulate their packument from + // the manifest, which they memoize on this.package, so it's very cheap + // already. + this.packumentCache = this.opts.packumentCache || null + // handle case when npm-package-arg guesses wrong. if (this.spec.type === 'tag' && this.spec.rawSpec === '' && @@ -64,11 +72,17 @@ class RegistryFetcher extends Fetcher { } } - packument () { + async packument () { + // note this might be either an in-flight promise for a request, + // or the actual packument, but we never want to make more than + // one request at a time for the same thing regardless. + if (this.packumentCache && this.packumentCache.has(this.packumentUrl)) + return this.packumentCache.get(this.packumentUrl) + // npm-registry-fetch the packument // set the appropriate header for corgis if fullMetadata isn't set // return the res.json() promise - return fetch(this.packumentUrl, { + const p = fetch(this.packumentUrl, { ...this.opts, headers: this[_headers](), spec: this.spec, @@ -77,8 +91,12 @@ class RegistryFetcher extends Fetcher { }).then(res => res.json().then(packument => { packument._cached = res.headers.has('x-local-cache') packument._contentLength = +res.headers.get('content-length') + if (this.packumentCache) + this.packumentCache.set(this.packumentUrl, packument) return packument })).catch(er => { + if (this.packumentCache) + this.packumentCache.delete(this.packumentUrl) if (er.code === 'E404' && !this.fullMetadata) { // possible that corgis are not supported by this registry this.fullMetadata = true @@ -86,6 +104,9 @@ class RegistryFetcher extends Fetcher { } throw er }) + if (this.packumentCache) + this.packumentCache.set(this.packumentUrl, p) + return p } manifest () { diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 085e8f66af175..8de6a07a24258 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "11.1.14", + "version": "11.2.1", "description": "JavaScript package downloader", "author": "Isaac Z. Schlueter (https://izs.me)", "bin": { @@ -13,7 +13,7 @@ "snap": "tap", "preversion": "npm test", "postversion": "npm publish", - "postpublish": "git push origin --follow-tags" + "prepublishOnly": "git push origin --follow-tags" }, "tap": { "timeout": 300, diff --git a/package-lock.json b/package-lock.json index 8d16f9a33df11..cd65aaa6c8b73 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "7.4.0", + "version": "7.4.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "npm", - "version": "7.4.0", + "version": "7.4.1", "bundleDependencies": [ "@npmcli/arborist", "@npmcli/ci-detect", @@ -354,7 +354,7 @@ ], "license": "Artistic-2.0", "dependencies": { - "@npmcli/arborist": "^2.0.3", + "@npmcli/arborist": "^2.0.5", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^1.2.8", "@npmcli/run-script": "^1.8.1", @@ -386,7 +386,7 @@ "libnpmsearch": "^3.1.0", "libnpmteam": "^2.0.2", "libnpmversion": "^1.0.7", - "make-fetch-happen": "^8.0.12", + "make-fetch-happen": "^8.0.13", "minipass": "^3.1.3", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", @@ -402,7 +402,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.1.14", + "pacote": "^11.2.1", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", @@ -682,15 +682,15 @@ } }, "node_modules/@npmcli/arborist": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.0.3.tgz", - "integrity": "sha512-iqahzDZaqdUyAHLG1SIG9jrbkLtT5xNbKX1ppAnx7mKx1u+BXYjkxi5ohewLAfyERH6IpODPAiRVc8c3kxA5jQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.0.5.tgz", + "integrity": "sha512-hUXn8XRChDG2Af4NpfPQpMiVbb0/IfhONdX1f1bcxjPXXKV54DMshU25tItcnKIeT5iKF1fqebQg8F3xHb5pCw==", "inBundle": true, "dependencies": { "@npmcli/installed-package-contents": "^1.0.5", "@npmcli/map-workspaces": "^1.0.1", - "@npmcli/metavuln-calculator": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/metavuln-calculator": "^1.0.1", + "@npmcli/move-file": "^1.1.0", "@npmcli/name-from-folder": "^1.0.1", "@npmcli/node-gyp": "^1.0.1", "@npmcli/run-script": "^1.8.1", @@ -703,7 +703,8 @@ "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", "npm-pick-manifest": "^6.1.0", - "pacote": "^11.1.14", + "npm-registry-fetch": "^9.0.0", + "pacote": "^11.2.1", "parse-conflict-json": "^1.1.1", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^1.0.1", @@ -788,9 +789,9 @@ } }, "node_modules/@npmcli/metavuln-calculator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.0.0.tgz", - "integrity": "sha512-BzFNWElLl99WqqkxBWHPBSZbKGbH4qJa0vICgRff+PWl0nIT0nDn0wJV3EBCDDWnrVqomH29ZENZc1SkRQ0C7A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.0.1.tgz", + "integrity": "sha512-ezAi4lvICICG613CPvavqCn76jjkiQS+Hag8qMQInLitEjIyzVBud6ATfYIhDcH3d8RnxtMXe3kvKs6+JqTnJA==", "inBundle": true, "dependencies": { "cacache": "^15.0.5", @@ -799,17 +800,30 @@ } }, "node_modules/@npmcli/move-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", - "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.0.tgz", + "integrity": "sha512-Iv2iq0JuyYjKeFkSR4LPaCdDZwlGK9X2cP/01nJcp3yMJ1FjNd9vpiEYvLUgzBxKPg2SFmaOhizoQsPc0LWeOQ==", "inBundle": true, "dependencies": { - "mkdirp": "^1.0.4" + "mkdirp": "^1.0.4", + "rimraf": "^2.7.1" }, "engines": { "node": ">=10" } }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "inBundle": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/@npmcli/name-from-folder": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", @@ -4480,9 +4494,9 @@ "dev": true }, "node_modules/make-fetch-happen": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.12.tgz", - "integrity": "sha512-cBD7yM72ltWEV+xlLlbimnh5qHwr+thAb/cZLiaZhicVVPVN63BikBvL5OR68+8+z2fvBOgck628vGJ2ulgF6g==", + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.13.tgz", + "integrity": "sha512-rQ5NijwwdU8tIaBrpTtSVrNCcAJfyDRcKBC76vOQlyJX588/88+TE+UpjWl4BgG7gCkp29wER7xcRqkeg+x64Q==", "inBundle": true, "dependencies": { "agentkeepalive": "^4.1.3", @@ -5333,9 +5347,9 @@ } }, "node_modules/pacote": { - "version": "11.1.14", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.1.14.tgz", - "integrity": "sha512-6c5OhQelaJFDfiw/Zd8MfGCvvFHurSdeGzufZMPvRFImdbNOYFciOINf3DtUNUaU3h98eCb749UyHDsgvL19+A==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.1.tgz", + "integrity": "sha512-r5GzxJdmyLdWxP98xYcXinyyj1MIO3wwgJeJpaIIql7rnMBkcLx5k3WKCPpknZU11ybOiXCrIjWuZt3le0Es9A==", "inBundle": true, "dependencies": { "@npmcli/git": "^2.0.1", @@ -9856,14 +9870,14 @@ } }, "@npmcli/arborist": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.0.3.tgz", - "integrity": "sha512-iqahzDZaqdUyAHLG1SIG9jrbkLtT5xNbKX1ppAnx7mKx1u+BXYjkxi5ohewLAfyERH6IpODPAiRVc8c3kxA5jQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.0.5.tgz", + "integrity": "sha512-hUXn8XRChDG2Af4NpfPQpMiVbb0/IfhONdX1f1bcxjPXXKV54DMshU25tItcnKIeT5iKF1fqebQg8F3xHb5pCw==", "requires": { "@npmcli/installed-package-contents": "^1.0.5", "@npmcli/map-workspaces": "^1.0.1", - "@npmcli/metavuln-calculator": "^1.0.0", - "@npmcli/move-file": "^1.0.1", + "@npmcli/metavuln-calculator": "^1.0.1", + "@npmcli/move-file": "^1.1.0", "@npmcli/name-from-folder": "^1.0.1", "@npmcli/node-gyp": "^1.0.1", "@npmcli/run-script": "^1.8.1", @@ -9876,7 +9890,8 @@ "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", "npm-pick-manifest": "^6.1.0", - "pacote": "^11.1.14", + "npm-registry-fetch": "^9.0.0", + "pacote": "^11.2.1", "parse-conflict-json": "^1.1.1", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^1.0.1", @@ -9944,9 +9959,9 @@ } }, "@npmcli/metavuln-calculator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.0.0.tgz", - "integrity": "sha512-BzFNWElLl99WqqkxBWHPBSZbKGbH4qJa0vICgRff+PWl0nIT0nDn0wJV3EBCDDWnrVqomH29ZENZc1SkRQ0C7A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-1.0.1.tgz", + "integrity": "sha512-ezAi4lvICICG613CPvavqCn76jjkiQS+Hag8qMQInLitEjIyzVBud6ATfYIhDcH3d8RnxtMXe3kvKs6+JqTnJA==", "requires": { "cacache": "^15.0.5", "pacote": "^11.1.11", @@ -9954,11 +9969,22 @@ } }, "@npmcli/move-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz", - "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.0.tgz", + "integrity": "sha512-Iv2iq0JuyYjKeFkSR4LPaCdDZwlGK9X2cP/01nJcp3yMJ1FjNd9vpiEYvLUgzBxKPg2SFmaOhizoQsPc0LWeOQ==", "requires": { - "mkdirp": "^1.0.4" + "mkdirp": "^1.0.4", + "rimraf": "^2.7.1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } } }, "@npmcli/name-from-folder": { @@ -12655,9 +12681,9 @@ "dev": true }, "make-fetch-happen": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.12.tgz", - "integrity": "sha512-cBD7yM72ltWEV+xlLlbimnh5qHwr+thAb/cZLiaZhicVVPVN63BikBvL5OR68+8+z2fvBOgck628vGJ2ulgF6g==", + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.13.tgz", + "integrity": "sha512-rQ5NijwwdU8tIaBrpTtSVrNCcAJfyDRcKBC76vOQlyJX588/88+TE+UpjWl4BgG7gCkp29wER7xcRqkeg+x64Q==", "requires": { "agentkeepalive": "^4.1.3", "cacache": "^15.0.5", @@ -13275,9 +13301,9 @@ } }, "pacote": { - "version": "11.1.14", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.1.14.tgz", - "integrity": "sha512-6c5OhQelaJFDfiw/Zd8MfGCvvFHurSdeGzufZMPvRFImdbNOYFciOINf3DtUNUaU3h98eCb749UyHDsgvL19+A==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.1.tgz", + "integrity": "sha512-r5GzxJdmyLdWxP98xYcXinyyj1MIO3wwgJeJpaIIql7rnMBkcLx5k3WKCPpknZU11ybOiXCrIjWuZt3le0Es9A==", "requires": { "@npmcli/git": "^2.0.1", "@npmcli/installed-package-contents": "^1.0.5", diff --git a/package.json b/package.json index 9f0aacbda2688..a3cec57979941 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "7.4.0", + "version": "7.4.1", "name": "npm", "description": "a package manager for JavaScript", "keywords": [ @@ -42,7 +42,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@npmcli/arborist": "^2.0.3", + "@npmcli/arborist": "^2.0.5", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^1.2.8", "@npmcli/run-script": "^1.8.1", @@ -74,7 +74,7 @@ "libnpmsearch": "^3.1.0", "libnpmteam": "^2.0.2", "libnpmversion": "^1.0.7", - "make-fetch-happen": "^8.0.12", + "make-fetch-happen": "^8.0.13", "minipass": "^3.1.3", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", @@ -90,7 +90,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.1.14", + "pacote": "^11.2.1", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", diff --git a/tap-snapshots/test-lib-link.js-TAP.test.js b/tap-snapshots/test-lib-link.js-TAP.test.js index de7f483b60de8..ab1d5c6b830fb 100644 --- a/tap-snapshots/test-lib-link.js-TAP.test.js +++ b/tap-snapshots/test-lib-link.js-TAP.test.js @@ -19,6 +19,11 @@ exports[`test/lib/link.js TAP link pkg already in global space > should create a ` +exports[`test/lib/link.js TAP link pkg already in global space when prefix is a symlink > should create a local symlink to global pkg 1`] = ` +{CWD}/test/lib/link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/scoped-linked + +` + exports[`test/lib/link.js TAP link to globalDir when in current working dir of pkg and no args > should create a global link to current pkg 1`] = ` {CWD}/test/lib/link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/global-prefix/lib/node_modules/test-pkg-link -> {CWD}/test/lib/link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/test-pkg-link diff --git a/test/lib/link.js b/test/lib/link.js index a478259f7b409..c39026a49163f 100644 --- a/test/lib/link.js +++ b/test/lib/link.js @@ -259,6 +259,64 @@ t.test('link pkg already in global space', (t) => { }) }) +t.test('link pkg already in global space when prefix is a symlink', (t) => { + t.plan(3) + + const testdir = t.testdir({ + 'global-prefix': t.fixture('symlink', './real-global-prefix'), + 'real-global-prefix': { + lib: { + node_modules: { + '@myscope': { + linked: t.fixture('symlink', '../../../../scoped-linked'), + }, + }, + }, + }, + 'scoped-linked': { + 'package.json': JSON.stringify({ + name: '@myscope/linked', + version: '1.0.0', + }), + }, + 'my-project': { + 'package.json': JSON.stringify({ + name: 'my-project', + version: '1.0.0', + }), + }, + }) + npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') + npm.prefix = resolve(testdir, 'my-project') + + npm.config.find = () => 'default' + + const _cwd = process.cwd() + process.chdir(npm.prefix) + + reifyOutput = async () => { + reifyOutput = undefined + process.chdir(_cwd) + npm.config.find = () => null + + const links = await printLinks({ + path: npm.prefix, + }) + + t.equal( + require(resolve(testdir, 'my-project', 'package.json')).dependencies, + undefined, + 'should not save to package.json upon linking' + ) + + t.matchSnapshot(links, 'should create a local symlink to global pkg') + } + + link(['@myscope/linked'], (err) => { + t.ifError(err, 'should not error out') + }) +}) + t.test('completion', (t) => { const testdir = t.testdir({ 'global-prefix': {